@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.
Files changed (110) hide show
  1. package/out/domain-lang-module.d.ts +0 -2
  2. package/out/domain-lang-module.js +3 -11
  3. package/out/domain-lang-module.js.map +1 -1
  4. package/out/generated/ast.d.ts +19 -8
  5. package/out/generated/ast.js +10 -1
  6. package/out/generated/ast.js.map +1 -1
  7. package/out/generated/grammar.d.ts +1 -1
  8. package/out/generated/grammar.js +123 -28
  9. package/out/generated/grammar.js.map +1 -1
  10. package/out/generated/module.d.ts +1 -1
  11. package/out/generated/module.js +1 -1
  12. package/out/index.d.ts +0 -3
  13. package/out/index.js +0 -5
  14. package/out/index.js.map +1 -1
  15. package/out/lsp/hover/domain-lang-hover.js +4 -0
  16. package/out/lsp/hover/domain-lang-hover.js.map +1 -1
  17. package/out/sdk/index.d.ts +1 -1
  18. package/out/sdk/loader-node.d.ts +3 -7
  19. package/out/sdk/loader-node.js +9 -24
  20. package/out/sdk/loader-node.js.map +1 -1
  21. package/out/sdk/types.d.ts +21 -0
  22. package/out/services/dependency-analyzer.d.ts +39 -3
  23. package/out/services/dependency-analyzer.js +47 -22
  24. package/out/services/dependency-analyzer.js.map +1 -1
  25. package/out/services/dependency-resolver.d.ts +45 -68
  26. package/out/services/dependency-resolver.js +43 -243
  27. package/out/services/dependency-resolver.js.map +1 -1
  28. package/out/services/git-url-resolver.browser.d.ts +12 -4
  29. package/out/services/git-url-resolver.browser.js +1 -5
  30. package/out/services/git-url-resolver.browser.js.map +1 -1
  31. package/out/services/git-url-resolver.d.ts +56 -22
  32. package/out/services/git-url-resolver.js +36 -70
  33. package/out/services/git-url-resolver.js.map +1 -1
  34. package/out/services/governance-validator.d.ts +37 -1
  35. package/out/services/governance-validator.js +10 -4
  36. package/out/services/governance-validator.js.map +1 -1
  37. package/out/services/import-resolver.d.ts +6 -65
  38. package/out/services/import-resolver.js +5 -223
  39. package/out/services/import-resolver.js.map +1 -1
  40. package/out/services/performance-optimizer.d.ts +1 -1
  41. package/out/services/workspace-manager.d.ts +10 -57
  42. package/out/services/workspace-manager.js +21 -187
  43. package/out/services/workspace-manager.js.map +1 -1
  44. package/out/syntaxes/domain-lang.monarch.js +1 -1
  45. package/out/syntaxes/domain-lang.monarch.js.map +1 -1
  46. package/out/utils/import-utils.d.ts +12 -4
  47. package/out/utils/import-utils.js +135 -35
  48. package/out/utils/import-utils.js.map +1 -1
  49. package/out/validation/constants.d.ts +0 -103
  50. package/out/validation/constants.js +1 -140
  51. package/out/validation/constants.js.map +1 -1
  52. package/out/validation/domain.js +1 -46
  53. package/out/validation/domain.js.map +1 -1
  54. package/out/validation/import.d.ts +22 -46
  55. package/out/validation/import.js +85 -187
  56. package/out/validation/import.js.map +1 -1
  57. package/out/validation/maps.js +6 -10
  58. package/out/validation/maps.js.map +1 -1
  59. package/out/validation/metadata.js +1 -5
  60. package/out/validation/metadata.js.map +1 -1
  61. package/package.json +6 -8
  62. package/src/domain-lang-module.ts +6 -18
  63. package/src/domain-lang.langium +12 -7
  64. package/src/generated/ast.ts +20 -7
  65. package/src/generated/grammar.ts +123 -28
  66. package/src/generated/module.ts +1 -1
  67. package/src/index.ts +0 -7
  68. package/src/lsp/hover/domain-lang-hover.ts +2 -0
  69. package/src/sdk/index.ts +2 -0
  70. package/src/sdk/loader-node.ts +9 -29
  71. package/src/sdk/types.ts +23 -0
  72. package/src/services/dependency-analyzer.ts +84 -24
  73. package/src/services/dependency-resolver.ts +84 -301
  74. package/src/services/git-url-resolver.browser.ts +14 -9
  75. package/src/services/git-url-resolver.ts +93 -86
  76. package/src/services/governance-validator.ts +47 -5
  77. package/src/services/import-resolver.ts +8 -270
  78. package/src/services/performance-optimizer.ts +1 -1
  79. package/src/services/workspace-manager.ts +46 -237
  80. package/src/syntaxes/domain-lang.monarch.ts +1 -1
  81. package/src/utils/import-utils.ts +160 -38
  82. package/src/validation/constants.ts +1 -181
  83. package/src/validation/domain.ts +1 -54
  84. package/src/validation/import.ts +104 -228
  85. package/src/validation/maps.ts +6 -10
  86. package/src/validation/metadata.ts +1 -5
  87. package/out/lsp/domain-lang-code-actions.d.ts +0 -55
  88. package/out/lsp/domain-lang-code-actions.js +0 -143
  89. package/out/lsp/domain-lang-code-actions.js.map +0 -1
  90. package/out/lsp/domain-lang-workspace-manager.d.ts +0 -21
  91. package/out/lsp/domain-lang-workspace-manager.js +0 -93
  92. package/out/lsp/domain-lang-workspace-manager.js.map +0 -1
  93. package/out/lsp/manifest-diagnostics.d.ts +0 -82
  94. package/out/lsp/manifest-diagnostics.js +0 -230
  95. package/out/lsp/manifest-diagnostics.js.map +0 -1
  96. package/out/services/semver.d.ts +0 -98
  97. package/out/services/semver.js +0 -195
  98. package/out/services/semver.js.map +0 -1
  99. package/out/services/types.d.ts +0 -340
  100. package/out/services/types.js +0 -46
  101. package/out/services/types.js.map +0 -1
  102. package/out/validation/manifest.d.ts +0 -144
  103. package/out/validation/manifest.js +0 -327
  104. package/out/validation/manifest.js.map +0 -1
  105. package/src/lsp/domain-lang-code-actions.ts +0 -189
  106. package/src/lsp/domain-lang-workspace-manager.ts +0 -104
  107. package/src/lsp/manifest-diagnostics.ts +0 -290
  108. package/src/services/semver.ts +0 -213
  109. package/src/services/types.ts +0 -415
  110. package/src/validation/manifest.ts +0 -439
@@ -1,224 +1,16 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import { URI } from 'langium';
4
1
  /**
5
- * ImportResolver resolves import statements using manifest-centric rules (PRS-010).
6
- *
7
- * Import Types (PRS-010):
8
- * - Local relative: ./path, ../path → Directory-first resolution
9
- * - Path aliases: @/path, @alias/path → Configurable in model.yaml paths section
10
- * - External: owner/package → Manifest dependencies
11
- *
12
- * Directory-First Resolution:
13
- * - ./types → ./types/index.dlang → ./types.dlang
14
- * - Module entry defaults to index.dlang (no model.yaml required)
2
+ * ImportResolver resolves import statements using WorkspaceManager and GitUrlResolver.
15
3
  */
16
4
  export class ImportResolver {
17
5
  constructor(services) {
18
6
  this.workspaceManager = services.imports.WorkspaceManager;
19
7
  }
20
8
  /**
21
- * Resolve an import specifier relative to a Langium document.
9
+ * Resolve an import URL to a file URI using the workspace's GitUrlResolver.
22
10
  */
23
- async resolveForDocument(document, specifier) {
24
- const baseDir = path.dirname(document.uri.fsPath);
25
- return this.resolveFrom(baseDir, specifier);
26
- }
27
- /**
28
- * Resolve an import specifier from a base directory (non-LSP contexts).
29
- */
30
- async resolveFrom(baseDir, specifier) {
31
- await this.workspaceManager.initialize(baseDir);
32
- // Local relative paths (./path or ../path) - directory-first resolution
33
- if (specifier.startsWith('./') || specifier.startsWith('../')) {
34
- const resolved = path.resolve(baseDir, specifier);
35
- return this.resolveLocalPath(resolved, specifier);
36
- }
37
- // Path aliases (@/path or @alias/path)
38
- if (specifier.startsWith('@')) {
39
- return this.resolvePathAlias(specifier);
40
- }
41
- // External dependency via manifest (owner/package format)
42
- return this.resolveExternalDependency(specifier);
43
- }
44
- /**
45
- * Resolves a path alias import.
46
- *
47
- * @param specifier - Import specifier starting with @ (e.g., "@/lib", "@shared/types")
48
- */
49
- async resolvePathAlias(specifier) {
50
- const aliases = await this.workspaceManager.getPathAliases();
51
- const root = this.workspaceManager.getWorkspaceRoot();
52
- // Find matching alias
53
- const aliasMatch = this.findMatchingAlias(specifier, aliases);
54
- if (aliasMatch) {
55
- const { alias: _alias, targetPath, remainder } = aliasMatch;
56
- const manifestPath = await this.workspaceManager.getManifestPath();
57
- const manifestDir = manifestPath ? path.dirname(manifestPath) : root;
58
- const resolvedBase = path.resolve(manifestDir, targetPath);
59
- const resolved = remainder ? path.join(resolvedBase, remainder) : resolvedBase;
60
- return this.resolveLocalPath(resolved, specifier);
61
- }
62
- // Default: @/ maps to workspace root (implicit)
63
- if (specifier.startsWith('@/')) {
64
- const relativePath = specifier.slice(2);
65
- const resolved = path.join(root, relativePath);
66
- return this.resolveLocalPath(resolved, specifier);
67
- }
68
- throw new Error(`Unknown path alias '${specifier.split('/')[0]}' in import '${specifier}'.\n` +
69
- `Hint: Define it in model.yaml paths section:\n` +
70
- ` paths:\n` +
71
- ` "${specifier.split('/')[0]}": "./some/path"`);
72
- }
73
- /**
74
- * Finds the longest matching alias for a specifier.
75
- */
76
- findMatchingAlias(specifier, aliases) {
77
- if (!aliases) {
78
- return undefined;
79
- }
80
- // Sort by length descending to match most specific alias first
81
- const sortedAliases = Object.entries(aliases)
82
- .sort(([a], [b]) => b.length - a.length);
83
- for (const [alias, targetPath] of sortedAliases) {
84
- // Exact match
85
- if (specifier === alias) {
86
- return { alias, targetPath, remainder: '' };
87
- }
88
- // Prefix match (alias + /)
89
- if (specifier.startsWith(`${alias}/`)) {
90
- return { alias, targetPath, remainder: specifier.slice(alias.length + 1) };
91
- }
92
- }
93
- return undefined;
94
- }
95
- /**
96
- * Resolves an external dependency via manifest.
97
- *
98
- * NEW FORMAT (PRS-010): Import specifier is owner/package format.
99
- */
100
- async resolveExternalDependency(specifier) {
101
- const manifest = await this.workspaceManager.getManifest();
102
- if (!manifest) {
103
- throw new Error(`External dependency '${specifier}' requires model.yaml.\n` +
104
- `Hint: Create model.yaml and add the dependency:\n` +
105
- ` dependencies:\n` +
106
- ` ${specifier}:\n` +
107
- ` ref: v1.0.0`);
108
- }
109
- const lock = await this.workspaceManager.getLockFile();
110
- if (!lock) {
111
- throw new Error(`Dependency '${specifier}' not installed.\n` +
112
- `Hint: Run 'dlang install' to fetch dependencies and generate model.lock.`);
113
- }
114
- const mapped = await this.workspaceManager.resolveDependencyImport(specifier);
115
- if (!mapped) {
116
- throw new Error(`Dependency '${specifier}' not found in model.yaml.\n` +
117
- `Hint: Add it to your dependencies:\n` +
118
- ` dependencies:\n` +
119
- ` ${specifier}:\n` +
120
- ` ref: v1.0.0`);
121
- }
122
- const git = await this.workspaceManager.getGitResolver();
123
- return git.resolve(mapped, { allowNetwork: false });
124
- }
125
- /**
126
- * Resolves a local path using directory-first resolution.
127
- *
128
- * Per PRS-010 (updated design):
129
- * - If path ends with .dlang → direct file import
130
- * - If no extension → directory-first:
131
- * 1. Try ./path/index.dlang (module default, no model.yaml required)
132
- * 2. Try ./path.dlang (file fallback)
133
- */
134
- async resolveLocalPath(resolved, original) {
135
- const ext = path.extname(resolved);
136
- if (ext === '.dlang') {
137
- // Direct file import
138
- await assertFileExists(resolved, original);
139
- return URI.file(resolved);
140
- }
141
- if (ext && ext !== '.dlang') {
142
- throw new Error(`Invalid file extension '${ext}' in import '${original}'.\n` +
143
- `Hint: DomainLang files must use the .dlang extension.`);
144
- }
145
- // No extension → directory-first resolution
146
- return this.resolveDirectoryFirst(resolved, original);
147
- }
148
- /**
149
- * Directory-first resolution: ./types → ./types/index.dlang → ./types.dlang
150
- *
151
- * Module entry defaults to index.dlang without requiring model.yaml.
152
- * If the directory has model.yaml with custom entry, use that.
153
- */
154
- async resolveDirectoryFirst(resolved, original) {
155
- // Step 1: Check if directory exists with index.dlang (or custom entry)
156
- const isDirectory = await this.isDirectory(resolved);
157
- if (isDirectory) {
158
- // Check for model.yaml to get custom entry point
159
- const moduleManifestPath = path.join(resolved, 'model.yaml');
160
- const entryPoint = await this.readModuleEntry(moduleManifestPath);
161
- const entryFile = path.join(resolved, entryPoint);
162
- if (await this.fileExists(entryFile)) {
163
- return URI.file(entryFile);
164
- }
165
- // Directory exists but no entry file
166
- throw new Error(`Module '${original}' is missing its entry file.\n` +
167
- `Expected: ${resolved}/${entryPoint}\n` +
168
- `Hint: Create '${entryPoint}' in the module directory, or specify a custom entry in model.yaml:\n` +
169
- ` model:\n` +
170
- ` entry: main.dlang`);
171
- }
172
- // Step 2: Try .dlang file fallback
173
- const fileWithExt = `${resolved}.dlang`;
174
- if (await this.fileExists(fileWithExt)) {
175
- return URI.file(fileWithExt);
176
- }
177
- // Neither directory nor file found
178
- throw new Error(`Cannot resolve import '${original}'.\n` +
179
- `Tried:\n` +
180
- ` • ${resolved}/index.dlang (directory module)\n` +
181
- ` • ${resolved}.dlang (file)\n` +
182
- `Hint: Check that the path is correct and the file exists.`);
183
- }
184
- /**
185
- * Reads the entry point from a module's model.yaml.
186
- * Defaults to index.dlang if no manifest or no entry specified.
187
- */
188
- async readModuleEntry(manifestPath) {
189
- try {
190
- const content = await fs.readFile(manifestPath, 'utf-8');
191
- const YAML = await import('yaml');
192
- const manifest = YAML.parse(content);
193
- return manifest?.model?.entry ?? 'index.dlang';
194
- }
195
- catch {
196
- return 'index.dlang';
197
- }
198
- }
199
- /**
200
- * Checks if a path is a directory.
201
- */
202
- async isDirectory(targetPath) {
203
- try {
204
- const stat = await fs.stat(targetPath);
205
- return stat.isDirectory();
206
- }
207
- catch {
208
- return false;
209
- }
210
- }
211
- /**
212
- * Checks if a file exists.
213
- */
214
- async fileExists(filePath) {
215
- try {
216
- await fs.access(filePath);
217
- return true;
218
- }
219
- catch {
220
- return false;
221
- }
11
+ async resolveImport(importUrl) {
12
+ const gitResolver = await this.workspaceManager.getGitResolver();
13
+ return gitResolver.resolve(importUrl);
222
14
  }
223
15
  /**
224
16
  * Get the current lock file (if loaded).
@@ -227,14 +19,4 @@ export class ImportResolver {
227
19
  return this.workspaceManager.getLockFile();
228
20
  }
229
21
  }
230
- async function assertFileExists(filePath, original) {
231
- try {
232
- await fs.access(filePath);
233
- }
234
- catch {
235
- throw new Error(`Import file not found: '${original}'.\\n` +
236
- `Resolved path: ${filePath}\\n` +
237
- `Hint: Check that the file exists and the path is correct.`);
238
- }
239
- }
240
22
  //# sourceMappingURL=import-resolver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"import-resolver.js","sourceRoot":"","sources":["../../src/services/import-resolver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"import-resolver.js","sourceRoot":"","sources":["../../src/services/import-resolver.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,OAAO,cAAc;IAGvB,YAAY,QAA4B;QACpC,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC;IAC9D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,SAAiB;QACjC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC;QACjE,OAAO,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW;QACb,OAAO,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC;IAC/C,CAAC;CACJ"}
@@ -7,7 +7,7 @@
7
7
  * - Cache warming strategies
8
8
  * - Stale cache detection
9
9
  */
10
- import type { LockFile } from './types.js';
10
+ import type { LockFile } from './git-url-resolver.js';
11
11
  /**
12
12
  * Performance optimizer with in-memory caching.
13
13
  */
@@ -1,5 +1,10 @@
1
1
  import { GitUrlResolver } from './git-url-resolver.js';
2
- import type { LockFile, ModelManifest, PathAliases, WorkspaceManagerOptions } from './types.js';
2
+ import type { LockFile } from './git-url-resolver.js';
3
+ export interface WorkspaceManagerOptions {
4
+ readonly autoResolve?: boolean;
5
+ readonly manifestFiles?: readonly string[];
6
+ readonly lockFiles?: readonly string[];
7
+ }
3
8
  /**
4
9
  * Coordinates workspace discovery, lock file lifecycle management, and git resolver configuration.
5
10
  */
@@ -28,11 +33,6 @@ export declare class WorkspaceManager {
28
33
  * Resolves the manifest file path within the workspace, if present.
29
34
  */
30
35
  getManifestPath(): Promise<string | undefined>;
31
- /**
32
- * Returns the parsed manifest when present, otherwise undefined.
33
- * Uses cached contents when unchanged on disk.
34
- */
35
- getManifest(): Promise<ModelManifest | undefined>;
36
36
  /**
37
37
  * Returns the cached lock file or triggers resolution when missing.
38
38
  */
@@ -45,24 +45,6 @@ export declare class WorkspaceManager {
45
45
  * Reloads the lock file from disk, updating the git resolver.
46
46
  */
47
47
  refreshLockFile(): Promise<LockFile | undefined>;
48
- /**
49
- * Invalidates all cached data (manifest and lock file).
50
- * Call this when config files change externally (e.g., from CLI commands).
51
- *
52
- * After invalidation, the next call to getManifest() or getLockFile()
53
- * will re-read from disk.
54
- */
55
- invalidateCache(): void;
56
- /**
57
- * Invalidates only the manifest cache.
58
- * Call this when model.yaml changes.
59
- */
60
- invalidateManifestCache(): void;
61
- /**
62
- * Invalidates only the lock file cache.
63
- * Call this when model.lock changes.
64
- */
65
- invalidateLockCache(): void;
66
48
  /**
67
49
  * Provides the shared git URL resolver configured with the current lock file.
68
50
  */
@@ -72,25 +54,12 @@ export declare class WorkspaceManager {
72
54
  */
73
55
  regenerateLockFile(): Promise<LockFile>;
74
56
  /**
75
- * Returns the path aliases from the manifest, if present.
76
- */
77
- getPathAliases(): Promise<PathAliases | undefined>;
78
- /**
79
- * Normalizes a dependency entry to its extended form.
80
- * Handles both short form (string version) and extended form (object).
81
- *
82
- * In the new format, the key IS the owner/package, so source is derived from key
83
- * ONLY for git dependencies (not for path-based local dependencies).
84
- */
85
- private normalizeDependency;
86
- /**
87
- * Resolves a manifest dependency to its git import string.
57
+ * Resolves a manifest dependency alias to its git import string.
88
58
  *
89
- * NEW FORMAT (PRS-010): Dependencies are keyed by owner/package directly
90
- * @param specifier - Import specifier (owner/package format, may include subpaths)
91
- * @returns Resolved git import string or undefined when not found
59
+ * @param aliasPath - Alias from import statement (may include subpaths)
60
+ * @returns Resolved git import string or undefined when alias is unknown
92
61
  */
93
- resolveDependencyImport(specifier: string): Promise<string | undefined>;
62
+ resolveDependencyImport(aliasPath: string): Promise<string | undefined>;
94
63
  private performInitialization;
95
64
  private ensureInitialized;
96
65
  private applyLockFile;
@@ -100,22 +69,6 @@ export declare class WorkspaceManager {
100
69
  private loadLockFileFromDisk;
101
70
  private tryReadLockFile;
102
71
  private loadManifest;
103
- /**
104
- * Validates manifest structure and dependency configurations.
105
- * Throws detailed errors for invalid manifests.
106
- *
107
- * Supports both new format (owner/package: version) and extended format.
108
- */
109
- private validateManifest;
110
- /**
111
- * Validates path aliases for security and correctness.
112
- */
113
- private validatePathAliases;
114
- /**
115
- * Validates local path dependencies for security.
116
- * Ensures paths don't escape workspace boundary.
117
- */
118
- private validateLocalPath;
119
72
  private parseJsonLockFile;
120
73
  private findWorkspaceRoot;
121
74
  private containsManifest;
@@ -57,14 +57,6 @@ export class WorkspaceManager {
57
57
  }
58
58
  return undefined;
59
59
  }
60
- /**
61
- * Returns the parsed manifest when present, otherwise undefined.
62
- * Uses cached contents when unchanged on disk.
63
- */
64
- async getManifest() {
65
- await this.ensureInitialized();
66
- return this.loadManifest();
67
- }
68
60
  /**
69
61
  * Returns the cached lock file or triggers resolution when missing.
70
62
  */
@@ -78,16 +70,11 @@ export class WorkspaceManager {
78
70
  this.lockFile = cached;
79
71
  }
80
72
  else {
81
- if (this.options.allowNetwork === false) {
82
- throw new Error('Lock file (model.lock) not found and network access is disabled.\n' +
83
- 'Hint: Run \'dlang install\' to generate the lock file.');
84
- }
85
73
  await this.generateLockFile();
86
74
  }
87
75
  }
88
76
  if (!this.lockFile) {
89
- throw new Error('Unable to resolve workspace lock file.\n' +
90
- 'Hint: Ensure model.yaml exists and run \'dlang install\' to generate model.lock.');
77
+ throw new Error('Unable to resolve workspace lock file.');
91
78
  }
92
79
  return this.lockFile;
93
80
  }
@@ -107,38 +94,6 @@ export class WorkspaceManager {
107
94
  this.applyLockFile(loaded);
108
95
  return this.lockFile;
109
96
  }
110
- /**
111
- * Invalidates all cached data (manifest and lock file).
112
- * Call this when config files change externally (e.g., from CLI commands).
113
- *
114
- * After invalidation, the next call to getManifest() or getLockFile()
115
- * will re-read from disk.
116
- */
117
- invalidateCache() {
118
- this.manifestCache = undefined;
119
- this.lockFile = undefined;
120
- // Re-apply undefined to git resolver to clear its lock file
121
- if (this.gitResolver) {
122
- this.gitResolver.setLockFile(undefined);
123
- }
124
- }
125
- /**
126
- * Invalidates only the manifest cache.
127
- * Call this when model.yaml changes.
128
- */
129
- invalidateManifestCache() {
130
- this.manifestCache = undefined;
131
- }
132
- /**
133
- * Invalidates only the lock file cache.
134
- * Call this when model.lock changes.
135
- */
136
- invalidateLockCache() {
137
- this.lockFile = undefined;
138
- if (this.gitResolver) {
139
- this.gitResolver.setLockFile(undefined);
140
- }
141
- }
142
97
  /**
143
98
  * Provides the shared git URL resolver configured with the current lock file.
144
99
  */
@@ -161,79 +116,42 @@ export class WorkspaceManager {
161
116
  return this.lockFile;
162
117
  }
163
118
  /**
164
- * Returns the path aliases from the manifest, if present.
165
- */
166
- async getPathAliases() {
167
- const manifest = await this.getManifest();
168
- return manifest?.paths;
169
- }
170
- /**
171
- * Normalizes a dependency entry to its extended form.
172
- * Handles both short form (string version) and extended form (object).
119
+ * Resolves a manifest dependency alias to its git import string.
173
120
  *
174
- * In the new format, the key IS the owner/package, so source is derived from key
175
- * ONLY for git dependencies (not for path-based local dependencies).
121
+ * @param aliasPath - Alias from import statement (may include subpaths)
122
+ * @returns Resolved git import string or undefined when alias is unknown
176
123
  */
177
- normalizeDependency(key, dep) {
178
- if (typeof dep === 'string') {
179
- // Short form: "owner/package": "v1.0.0" or "main"
180
- // Key is the source (owner/package format)
181
- return { source: key, ref: dep };
182
- }
183
- // Extended form:
184
- // - If has source: use as-is
185
- // - If has path: it's a local dep, don't set source
186
- // - If neither: derive source from key (owner/package becomes source)
187
- if (dep.source || dep.path) {
188
- return dep;
189
- }
190
- return { ...dep, source: key };
191
- }
192
- /**
193
- * Resolves a manifest dependency to its git import string.
194
- *
195
- * NEW FORMAT (PRS-010): Dependencies are keyed by owner/package directly
196
- * @param specifier - Import specifier (owner/package format, may include subpaths)
197
- * @returns Resolved git import string or undefined when not found
198
- */
199
- async resolveDependencyImport(specifier) {
124
+ async resolveDependencyImport(aliasPath) {
200
125
  await this.ensureInitialized();
201
126
  const manifest = await this.loadManifest();
202
127
  const dependencies = manifest?.dependencies;
203
128
  if (!dependencies) {
204
129
  return undefined;
205
130
  }
206
- // NEW: Dependencies are keyed by owner/package (e.g., "domainlang/core")
207
- // Import specifier is also owner/package, potentially with subpath
208
- for (const [key, dep] of Object.entries(dependencies)) {
209
- const normalized = this.normalizeDependency(key, dep);
210
- // Skip path-based dependencies (handled by path aliases)
211
- if (normalized.path) {
212
- continue;
213
- }
214
- if (!normalized.source) {
131
+ for (const [alias, dep] of Object.entries(dependencies)) {
132
+ if (!dep?.source) {
215
133
  continue;
216
134
  }
217
- // Match if specifier equals key or starts with key/
218
- if (specifier === key || specifier.startsWith(`${key}/`)) {
219
- const suffix = specifier.slice(key.length);
220
- const ref = normalized.ref ?? '';
221
- const refSegment = ref
222
- ? (ref.startsWith('@') ? ref : `@${ref}`)
135
+ if (aliasPath === alias || aliasPath.startsWith(`${alias}/`)) {
136
+ const suffix = aliasPath.slice(alias.length);
137
+ const version = dep.version ?? '';
138
+ const versionSegment = version
139
+ ? (version.startsWith('@') ? version : `@${version}`)
223
140
  : '';
224
- return `${normalized.source}${refSegment}${suffix}`;
141
+ return `${dep.source}${versionSegment}${suffix}`;
225
142
  }
226
143
  }
227
144
  return undefined;
228
145
  }
229
146
  async performInitialization(startPath) {
230
- this.workspaceRoot = await this.findWorkspaceRoot(startPath) ?? path.resolve(startPath);
231
- // Per PRS-010: Project-local cache at .dlang/packages/ (like node_modules)
232
- const cacheDir = path.join(this.workspaceRoot, '.dlang', 'packages');
233
- this.gitResolver = new GitUrlResolver(cacheDir);
147
+ this.workspaceRoot = await this.findWorkspaceRoot(startPath);
148
+ if (!this.workspaceRoot) {
149
+ throw new Error('Workspace root (directory with model.yaml) not found.');
150
+ }
151
+ this.gitResolver = new GitUrlResolver();
234
152
  const loaded = await this.loadLockFileFromDisk();
235
153
  this.applyLockFile(loaded);
236
- if (!this.lockFile && this.options.autoResolve !== false && this.options.allowNetwork !== false) {
154
+ if (!this.lockFile && this.options.autoResolve !== false) {
237
155
  await this.generateLockFile();
238
156
  }
239
157
  }
@@ -332,8 +250,6 @@ export class WorkspaceManager {
332
250
  }
333
251
  const content = await fs.readFile(manifestPath, 'utf-8');
334
252
  const manifest = (YAML.parse(content) ?? {});
335
- // Validate manifest structure
336
- this.validateManifest(manifest, manifestPath);
337
253
  this.manifestCache = {
338
254
  manifest,
339
255
  path: manifestPath,
@@ -349,98 +265,16 @@ export class WorkspaceManager {
349
265
  throw error;
350
266
  }
351
267
  }
352
- /**
353
- * Validates manifest structure and dependency configurations.
354
- * Throws detailed errors for invalid manifests.
355
- *
356
- * Supports both new format (owner/package: version) and extended format.
357
- */
358
- validateManifest(manifest, manifestPath) {
359
- // Validate path aliases
360
- if (manifest.paths) {
361
- this.validatePathAliases(manifest.paths, manifestPath);
362
- }
363
- if (!manifest.dependencies) {
364
- return; // No dependencies to validate
365
- }
366
- for (const [key, dep] of Object.entries(manifest.dependencies)) {
367
- const normalized = this.normalizeDependency(key, dep);
368
- // Validate mutually exclusive source and path
369
- if (normalized.source && normalized.path) {
370
- throw new Error(`Invalid dependency '${key}' in ${manifestPath}:\n` +
371
- `Cannot specify both 'source' and 'path'.\n` +
372
- `Hint: Use 'source' for git dependencies or 'path' for local workspace dependencies.`);
373
- }
374
- // For string format, source is always derived from key (valid)
375
- // For extended format without source or path, error
376
- if (typeof dep !== 'string' && !normalized.source && !normalized.path) {
377
- throw new Error(`Invalid dependency '${key}' in ${manifestPath}:\n` +
378
- `Must specify either 'source' or 'path'.\n` +
379
- `Hint: Add 'source: owner/repo' for git dependencies, or 'path: ./local/path' for local packages.`);
380
- }
381
- // Validate path is relative and within workspace
382
- if (normalized.path) {
383
- this.validateLocalPath(normalized.path, key, manifestPath);
384
- }
385
- // Validate source has ref when specified
386
- if (normalized.source && !normalized.ref) {
387
- throw new Error(`Invalid dependency '${key}' in ${manifestPath}:\n` +
388
- `Git dependencies must specify a 'ref' (git reference).\n` +
389
- `Hint: Add 'ref: v1.0.0' (tag), 'ref: main' (branch), or a commit SHA.`);
390
- }
391
- }
392
- }
393
- /**
394
- * Validates path aliases for security and correctness.
395
- */
396
- validatePathAliases(paths, manifestPath) {
397
- for (const [alias, targetPath] of Object.entries(paths)) {
398
- // Validate alias starts with @
399
- if (!alias.startsWith('@')) {
400
- throw new Error(`Invalid path alias '${alias}' in ${manifestPath}:\n` +
401
- `Path aliases must start with '@'.\n` +
402
- `Hint: Rename to '@${alias}' in your model.yaml paths section.`);
403
- }
404
- // Validate target path doesn't escape workspace
405
- this.validateLocalPath(targetPath, alias, manifestPath);
406
- }
407
- }
408
- /**
409
- * Validates local path dependencies for security.
410
- * Ensures paths don't escape workspace boundary.
411
- */
412
- validateLocalPath(localPath, alias, manifestPath) {
413
- // Reject absolute paths
414
- if (path.isAbsolute(localPath)) {
415
- throw new Error(`Invalid local path '${alias}' in ${manifestPath}:\n` +
416
- `Cannot use absolute path '${localPath}'.\n` +
417
- `Hint: Use relative paths (e.g., './lib', '../shared') for local dependencies.`);
418
- }
419
- // Resolve path relative to manifest directory
420
- const manifestDir = path.dirname(manifestPath);
421
- const resolvedPath = path.resolve(manifestDir, localPath);
422
- const workspaceRoot = this.workspaceRoot || manifestDir;
423
- // Check if resolved path is within workspace
424
- const relativePath = path.relative(workspaceRoot, resolvedPath);
425
- if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
426
- throw new Error(`Invalid local path '${alias}' in ${manifestPath}:\n` +
427
- `Path '${localPath}' resolves outside workspace boundary.\n` +
428
- `Resolved: ${resolvedPath}\n` +
429
- `Workspace: ${workspaceRoot}\n` +
430
- `Hint: Local dependencies must be within the workspace. Consider moving the dependency or using a git-based source.`);
431
- }
432
- }
433
268
  parseJsonLockFile(content) {
434
269
  const parsed = JSON.parse(content);
435
270
  const version = typeof parsed.version === 'string' ? parsed.version : '1';
436
271
  const dependencies = {};
437
272
  for (const [key, value] of Object.entries(parsed.dependencies ?? {})) {
438
- if (!value || typeof value.ref !== 'string' || typeof value.resolved !== 'string' || typeof value.commit !== 'string') {
273
+ if (!value || typeof value.version !== 'string' || typeof value.resolved !== 'string' || typeof value.commit !== 'string') {
439
274
  continue;
440
275
  }
441
276
  dependencies[key] = {
442
- ref: value.ref,
443
- refType: value.refType ?? 'commit', // Default to commit for backwards compatibility
277
+ version: value.version,
444
278
  resolved: value.resolved,
445
279
  commit: value.commit,
446
280
  integrity: value.integrity,