@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.
Files changed (212) hide show
  1. package/README.md +163 -0
  2. package/out/ast-augmentation.d.ts +6 -0
  3. package/out/ast-augmentation.js +2 -0
  4. package/out/ast-augmentation.js.map +1 -0
  5. package/out/domain-lang-module.d.ts +57 -0
  6. package/out/domain-lang-module.js +67 -0
  7. package/out/domain-lang-module.js.map +1 -0
  8. package/out/generated/ast.d.ts +759 -0
  9. package/out/generated/ast.js +556 -0
  10. package/out/generated/ast.js.map +1 -0
  11. package/out/generated/grammar.d.ts +6 -0
  12. package/out/generated/grammar.js +2407 -0
  13. package/out/generated/grammar.js.map +1 -0
  14. package/out/generated/module.d.ts +13 -0
  15. package/out/generated/module.js +21 -0
  16. package/out/generated/module.js.map +1 -0
  17. package/out/index.d.ts +16 -0
  18. package/out/index.js +22 -0
  19. package/out/index.js.map +1 -0
  20. package/out/lsp/domain-lang-code-actions.d.ts +55 -0
  21. package/out/lsp/domain-lang-code-actions.js +143 -0
  22. package/out/lsp/domain-lang-code-actions.js.map +1 -0
  23. package/out/lsp/domain-lang-completion.d.ts +37 -0
  24. package/out/lsp/domain-lang-completion.js +452 -0
  25. package/out/lsp/domain-lang-completion.js.map +1 -0
  26. package/out/lsp/domain-lang-formatter.d.ts +15 -0
  27. package/out/lsp/domain-lang-formatter.js +43 -0
  28. package/out/lsp/domain-lang-formatter.js.map +1 -0
  29. package/out/lsp/domain-lang-naming.d.ts +34 -0
  30. package/out/lsp/domain-lang-naming.js +49 -0
  31. package/out/lsp/domain-lang-naming.js.map +1 -0
  32. package/out/lsp/domain-lang-scope.d.ts +59 -0
  33. package/out/lsp/domain-lang-scope.js +102 -0
  34. package/out/lsp/domain-lang-scope.js.map +1 -0
  35. package/out/lsp/domain-lang-workspace-manager.d.ts +21 -0
  36. package/out/lsp/domain-lang-workspace-manager.js +93 -0
  37. package/out/lsp/domain-lang-workspace-manager.js.map +1 -0
  38. package/out/lsp/hover/ddd-pattern-explanations.d.ts +50 -0
  39. package/out/lsp/hover/ddd-pattern-explanations.js +196 -0
  40. package/out/lsp/hover/ddd-pattern-explanations.js.map +1 -0
  41. package/out/lsp/hover/domain-lang-hover.d.ts +19 -0
  42. package/out/lsp/hover/domain-lang-hover.js +302 -0
  43. package/out/lsp/hover/domain-lang-hover.js.map +1 -0
  44. package/out/lsp/hover/domain-lang-keywords.d.ts +13 -0
  45. package/out/lsp/hover/domain-lang-keywords.js +47 -0
  46. package/out/lsp/hover/domain-lang-keywords.js.map +1 -0
  47. package/out/lsp/manifest-diagnostics.d.ts +82 -0
  48. package/out/lsp/manifest-diagnostics.js +230 -0
  49. package/out/lsp/manifest-diagnostics.js.map +1 -0
  50. package/out/main-browser.d.ts +1 -0
  51. package/out/main-browser.js +11 -0
  52. package/out/main-browser.js.map +1 -0
  53. package/out/main.d.ts +1 -0
  54. package/out/main.js +74 -0
  55. package/out/main.js.map +1 -0
  56. package/out/sdk/ast-augmentation.d.ts +136 -0
  57. package/out/sdk/ast-augmentation.js +62 -0
  58. package/out/sdk/ast-augmentation.js.map +1 -0
  59. package/out/sdk/index.d.ts +94 -0
  60. package/out/sdk/index.js +97 -0
  61. package/out/sdk/index.js.map +1 -0
  62. package/out/sdk/indexes.d.ts +16 -0
  63. package/out/sdk/indexes.js +97 -0
  64. package/out/sdk/indexes.js.map +1 -0
  65. package/out/sdk/loader-node.d.ts +51 -0
  66. package/out/sdk/loader-node.js +119 -0
  67. package/out/sdk/loader-node.js.map +1 -0
  68. package/out/sdk/loader.d.ts +49 -0
  69. package/out/sdk/loader.js +85 -0
  70. package/out/sdk/loader.js.map +1 -0
  71. package/out/sdk/patterns.d.ts +93 -0
  72. package/out/sdk/patterns.js +123 -0
  73. package/out/sdk/patterns.js.map +1 -0
  74. package/out/sdk/query.d.ts +90 -0
  75. package/out/sdk/query.js +679 -0
  76. package/out/sdk/query.js.map +1 -0
  77. package/out/sdk/resolution.d.ts +52 -0
  78. package/out/sdk/resolution.js +68 -0
  79. package/out/sdk/resolution.js.map +1 -0
  80. package/out/sdk/types.d.ts +280 -0
  81. package/out/sdk/types.js +8 -0
  82. package/out/sdk/types.js.map +1 -0
  83. package/out/services/dependency-analyzer.d.ts +58 -0
  84. package/out/services/dependency-analyzer.js +254 -0
  85. package/out/services/dependency-analyzer.js.map +1 -0
  86. package/out/services/dependency-resolver.d.ts +146 -0
  87. package/out/services/dependency-resolver.js +452 -0
  88. package/out/services/dependency-resolver.js.map +1 -0
  89. package/out/services/git-url-resolver.browser.d.ts +10 -0
  90. package/out/services/git-url-resolver.browser.js +19 -0
  91. package/out/services/git-url-resolver.browser.js.map +1 -0
  92. package/out/services/git-url-resolver.d.ts +158 -0
  93. package/out/services/git-url-resolver.js +416 -0
  94. package/out/services/git-url-resolver.js.map +1 -0
  95. package/out/services/governance-validator.d.ts +44 -0
  96. package/out/services/governance-validator.js +153 -0
  97. package/out/services/governance-validator.js.map +1 -0
  98. package/out/services/import-resolver.d.ts +77 -0
  99. package/out/services/import-resolver.js +240 -0
  100. package/out/services/import-resolver.js.map +1 -0
  101. package/out/services/performance-optimizer.d.ts +60 -0
  102. package/out/services/performance-optimizer.js +140 -0
  103. package/out/services/performance-optimizer.js.map +1 -0
  104. package/out/services/relationship-inference.d.ts +11 -0
  105. package/out/services/relationship-inference.js +98 -0
  106. package/out/services/relationship-inference.js.map +1 -0
  107. package/out/services/semver.d.ts +98 -0
  108. package/out/services/semver.js +195 -0
  109. package/out/services/semver.js.map +1 -0
  110. package/out/services/types.d.ts +340 -0
  111. package/out/services/types.js +46 -0
  112. package/out/services/types.js.map +1 -0
  113. package/out/services/workspace-manager.d.ts +123 -0
  114. package/out/services/workspace-manager.js +489 -0
  115. package/out/services/workspace-manager.js.map +1 -0
  116. package/out/syntaxes/domain-lang.monarch.d.ts +76 -0
  117. package/out/syntaxes/domain-lang.monarch.js +29 -0
  118. package/out/syntaxes/domain-lang.monarch.js.map +1 -0
  119. package/out/utils/import-utils.d.ts +49 -0
  120. package/out/utils/import-utils.js +128 -0
  121. package/out/utils/import-utils.js.map +1 -0
  122. package/out/validation/bounded-context.d.ts +11 -0
  123. package/out/validation/bounded-context.js +79 -0
  124. package/out/validation/bounded-context.js.map +1 -0
  125. package/out/validation/classification.d.ts +3 -0
  126. package/out/validation/classification.js +3 -0
  127. package/out/validation/classification.js.map +1 -0
  128. package/out/validation/constants.d.ts +180 -0
  129. package/out/validation/constants.js +235 -0
  130. package/out/validation/constants.js.map +1 -0
  131. package/out/validation/domain-lang-validator.d.ts +2 -0
  132. package/out/validation/domain-lang-validator.js +27 -0
  133. package/out/validation/domain-lang-validator.js.map +1 -0
  134. package/out/validation/domain.d.ts +11 -0
  135. package/out/validation/domain.js +63 -0
  136. package/out/validation/domain.js.map +1 -0
  137. package/out/validation/import.d.ts +68 -0
  138. package/out/validation/import.js +237 -0
  139. package/out/validation/import.js.map +1 -0
  140. package/out/validation/manifest.d.ts +144 -0
  141. package/out/validation/manifest.js +327 -0
  142. package/out/validation/manifest.js.map +1 -0
  143. package/out/validation/maps.d.ts +21 -0
  144. package/out/validation/maps.js +60 -0
  145. package/out/validation/maps.js.map +1 -0
  146. package/out/validation/metadata.d.ts +7 -0
  147. package/out/validation/metadata.js +16 -0
  148. package/out/validation/metadata.js.map +1 -0
  149. package/out/validation/model.d.ts +12 -0
  150. package/out/validation/model.js +29 -0
  151. package/out/validation/model.js.map +1 -0
  152. package/out/validation/relationships.d.ts +12 -0
  153. package/out/validation/relationships.js +94 -0
  154. package/out/validation/relationships.js.map +1 -0
  155. package/out/validation/shared.d.ts +6 -0
  156. package/out/validation/shared.js +12 -0
  157. package/out/validation/shared.js.map +1 -0
  158. package/package.json +110 -0
  159. package/src/ast-augmentation.ts +5 -0
  160. package/src/domain-lang-module.ts +112 -0
  161. package/src/domain-lang.langium +351 -0
  162. package/src/generated/ast.ts +986 -0
  163. package/src/generated/grammar.ts +2409 -0
  164. package/src/generated/module.ts +25 -0
  165. package/src/index.ts +24 -0
  166. package/src/lsp/domain-lang-code-actions.ts +189 -0
  167. package/src/lsp/domain-lang-completion.ts +514 -0
  168. package/src/lsp/domain-lang-formatter.ts +51 -0
  169. package/src/lsp/domain-lang-naming.ts +56 -0
  170. package/src/lsp/domain-lang-scope.ts +137 -0
  171. package/src/lsp/domain-lang-workspace-manager.ts +104 -0
  172. package/src/lsp/hover/ddd-pattern-explanations.ts +237 -0
  173. package/src/lsp/hover/domain-lang-hover.ts +338 -0
  174. package/src/lsp/hover/domain-lang-keywords.ts +50 -0
  175. package/src/lsp/manifest-diagnostics.ts +290 -0
  176. package/src/main-browser.ts +15 -0
  177. package/src/main.ts +85 -0
  178. package/src/sdk/README.md +297 -0
  179. package/src/sdk/ast-augmentation.ts +157 -0
  180. package/src/sdk/index.ts +126 -0
  181. package/src/sdk/indexes.ts +155 -0
  182. package/src/sdk/loader-node.ts +146 -0
  183. package/src/sdk/loader.ts +99 -0
  184. package/src/sdk/patterns.ts +147 -0
  185. package/src/sdk/query.ts +802 -0
  186. package/src/sdk/resolution.ts +78 -0
  187. package/src/sdk/types.ts +323 -0
  188. package/src/services/dependency-analyzer.ts +321 -0
  189. package/src/services/dependency-resolver.ts +551 -0
  190. package/src/services/git-url-resolver.browser.ts +26 -0
  191. package/src/services/git-url-resolver.ts +517 -0
  192. package/src/services/governance-validator.ts +177 -0
  193. package/src/services/import-resolver.ts +292 -0
  194. package/src/services/performance-optimizer.ts +170 -0
  195. package/src/services/relationship-inference.ts +121 -0
  196. package/src/services/semver.ts +213 -0
  197. package/src/services/types.ts +415 -0
  198. package/src/services/workspace-manager.ts +607 -0
  199. package/src/syntaxes/domain-lang.monarch.ts +29 -0
  200. package/src/utils/import-utils.ts +152 -0
  201. package/src/validation/bounded-context.ts +99 -0
  202. package/src/validation/classification.ts +5 -0
  203. package/src/validation/constants.ts +304 -0
  204. package/src/validation/domain-lang-validator.ts +33 -0
  205. package/src/validation/domain.ts +77 -0
  206. package/src/validation/import.ts +295 -0
  207. package/src/validation/manifest.ts +439 -0
  208. package/src/validation/maps.ts +76 -0
  209. package/src/validation/metadata.ts +18 -0
  210. package/src/validation/model.ts +37 -0
  211. package/src/validation/relationships.ts +154 -0
  212. package/src/validation/shared.ts +14 -0
@@ -0,0 +1,77 @@
1
+ import { URI, type LangiumDocument } from 'langium';
2
+ import type { DomainLangServices } from '../domain-lang-module.js';
3
+ import type { LockFile } from './types.js';
4
+ /**
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)
15
+ */
16
+ export declare class ImportResolver {
17
+ private readonly workspaceManager;
18
+ constructor(services: DomainLangServices);
19
+ /**
20
+ * Resolve an import specifier relative to a Langium document.
21
+ */
22
+ resolveForDocument(document: LangiumDocument, specifier: string): Promise<URI>;
23
+ /**
24
+ * Resolve an import specifier from a base directory (non-LSP contexts).
25
+ */
26
+ resolveFrom(baseDir: string, specifier: string): Promise<URI>;
27
+ /**
28
+ * Resolves a path alias import.
29
+ *
30
+ * @param specifier - Import specifier starting with @ (e.g., "@/lib", "@shared/types")
31
+ */
32
+ private resolvePathAlias;
33
+ /**
34
+ * Finds the longest matching alias for a specifier.
35
+ */
36
+ private findMatchingAlias;
37
+ /**
38
+ * Resolves an external dependency via manifest.
39
+ *
40
+ * NEW FORMAT (PRS-010): Import specifier is owner/package format.
41
+ */
42
+ private resolveExternalDependency;
43
+ /**
44
+ * Resolves a local path using directory-first resolution.
45
+ *
46
+ * Per PRS-010 (updated design):
47
+ * - If path ends with .dlang → direct file import
48
+ * - If no extension → directory-first:
49
+ * 1. Try ./path/index.dlang (module default, no model.yaml required)
50
+ * 2. Try ./path.dlang (file fallback)
51
+ */
52
+ private resolveLocalPath;
53
+ /**
54
+ * Directory-first resolution: ./types → ./types/index.dlang → ./types.dlang
55
+ *
56
+ * Module entry defaults to index.dlang without requiring model.yaml.
57
+ * If the directory has model.yaml with custom entry, use that.
58
+ */
59
+ private resolveDirectoryFirst;
60
+ /**
61
+ * Reads the entry point from a module's model.yaml.
62
+ * Defaults to index.dlang if no manifest or no entry specified.
63
+ */
64
+ private readModuleEntry;
65
+ /**
66
+ * Checks if a path is a directory.
67
+ */
68
+ private isDirectory;
69
+ /**
70
+ * Checks if a file exists.
71
+ */
72
+ private fileExists;
73
+ /**
74
+ * Get the current lock file (if loaded).
75
+ */
76
+ getLockFile(): Promise<LockFile | undefined>;
77
+ }
@@ -0,0 +1,240 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { URI } from 'langium';
4
+ /**
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)
15
+ */
16
+ export class ImportResolver {
17
+ constructor(services) {
18
+ this.workspaceManager = services.imports.WorkspaceManager;
19
+ }
20
+ /**
21
+ * Resolve an import specifier relative to a Langium document.
22
+ */
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
+ }
222
+ }
223
+ /**
224
+ * Get the current lock file (if loaded).
225
+ */
226
+ async getLockFile() {
227
+ return this.workspaceManager.getLockFile();
228
+ }
229
+ }
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
+ //# sourceMappingURL=import-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-resolver.js","sourceRoot":"","sources":["../../src/services/import-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Performance Optimization Service
3
+ *
4
+ * Provides caching and optimization strategies for dependency resolution:
5
+ * - In-memory caching of frequently accessed lock files
6
+ * - Parallel dependency downloads
7
+ * - Cache warming strategies
8
+ * - Stale cache detection
9
+ */
10
+ import type { LockFile } from './types.js';
11
+ /**
12
+ * Performance optimizer with in-memory caching.
13
+ */
14
+ export declare class PerformanceOptimizer {
15
+ private lockFileCache;
16
+ private manifestCache;
17
+ private readonly cacheTTL;
18
+ constructor(options?: {
19
+ cacheTTL?: number;
20
+ });
21
+ /**
22
+ * Gets a lock file from cache or loads it from disk.
23
+ */
24
+ getCachedLockFile(workspaceRoot: string): Promise<LockFile | undefined>;
25
+ /**
26
+ * Gets a manifest file from cache or loads it from disk.
27
+ */
28
+ getCachedManifest(manifestPath: string): Promise<unknown | undefined>;
29
+ /**
30
+ * Invalidates cache for a specific workspace.
31
+ */
32
+ invalidateCache(workspaceRoot: string): void;
33
+ /**
34
+ * Clears all caches.
35
+ */
36
+ clearAllCaches(): void;
37
+ /**
38
+ * Gets cache statistics.
39
+ */
40
+ getCacheStats(): {
41
+ lockFiles: number;
42
+ manifests: number;
43
+ };
44
+ /**
45
+ * Detects if cached files are stale compared to disk.
46
+ */
47
+ detectStaleCaches(): Promise<string[]>;
48
+ /**
49
+ * Normalizes a file path for cache keys.
50
+ */
51
+ private normalizePath;
52
+ }
53
+ /**
54
+ * Gets the global performance optimizer instance.
55
+ */
56
+ export declare function getGlobalOptimizer(): PerformanceOptimizer;
57
+ /**
58
+ * Resets the global optimizer (useful for testing).
59
+ */
60
+ export declare function resetGlobalOptimizer(): void;
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Performance Optimization Service
3
+ *
4
+ * Provides caching and optimization strategies for dependency resolution:
5
+ * - In-memory caching of frequently accessed lock files
6
+ * - Parallel dependency downloads
7
+ * - Cache warming strategies
8
+ * - Stale cache detection
9
+ */
10
+ import path from 'node:path';
11
+ import fs from 'node:fs/promises';
12
+ /**
13
+ * Performance optimizer with in-memory caching.
14
+ */
15
+ export class PerformanceOptimizer {
16
+ constructor(options = {}) {
17
+ this.lockFileCache = new Map();
18
+ this.manifestCache = new Map();
19
+ // Default TTL: 5 minutes
20
+ this.cacheTTL = options.cacheTTL ?? 5 * 60 * 1000;
21
+ }
22
+ /**
23
+ * Gets a lock file from cache or loads it from disk.
24
+ */
25
+ async getCachedLockFile(workspaceRoot) {
26
+ const cacheKey = this.normalizePath(workspaceRoot);
27
+ const cached = this.lockFileCache.get(cacheKey);
28
+ // Check if cache is still valid
29
+ if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
30
+ return cached.value;
31
+ }
32
+ // Load from disk
33
+ const lockPath = path.join(workspaceRoot, 'model.lock');
34
+ try {
35
+ const content = await fs.readFile(lockPath, 'utf-8');
36
+ const lockFile = JSON.parse(content);
37
+ // Cache it
38
+ this.lockFileCache.set(cacheKey, {
39
+ value: lockFile,
40
+ timestamp: Date.now(),
41
+ });
42
+ return lockFile;
43
+ }
44
+ catch {
45
+ return undefined;
46
+ }
47
+ }
48
+ /**
49
+ * Gets a manifest file from cache or loads it from disk.
50
+ */
51
+ async getCachedManifest(manifestPath) {
52
+ const cacheKey = this.normalizePath(manifestPath);
53
+ const cached = this.manifestCache.get(cacheKey);
54
+ if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
55
+ return cached.value;
56
+ }
57
+ try {
58
+ const content = await fs.readFile(manifestPath, 'utf-8');
59
+ const manifest = JSON.parse(content);
60
+ this.manifestCache.set(cacheKey, {
61
+ value: manifest,
62
+ timestamp: Date.now(),
63
+ });
64
+ return manifest;
65
+ }
66
+ catch {
67
+ return undefined;
68
+ }
69
+ }
70
+ /**
71
+ * Invalidates cache for a specific workspace.
72
+ */
73
+ invalidateCache(workspaceRoot) {
74
+ const cacheKey = this.normalizePath(workspaceRoot);
75
+ this.lockFileCache.delete(cacheKey);
76
+ }
77
+ /**
78
+ * Clears all caches.
79
+ */
80
+ clearAllCaches() {
81
+ this.lockFileCache.clear();
82
+ this.manifestCache.clear();
83
+ }
84
+ /**
85
+ * Gets cache statistics.
86
+ */
87
+ getCacheStats() {
88
+ return {
89
+ lockFiles: this.lockFileCache.size,
90
+ manifests: this.manifestCache.size,
91
+ };
92
+ }
93
+ /**
94
+ * Detects if cached files are stale compared to disk.
95
+ */
96
+ async detectStaleCaches() {
97
+ const stale = [];
98
+ for (const [workspaceRoot] of this.lockFileCache) {
99
+ const lockPath = path.join(workspaceRoot, 'model.lock');
100
+ try {
101
+ const stat = await fs.stat(lockPath);
102
+ const cached = this.lockFileCache.get(workspaceRoot);
103
+ if (cached && stat.mtimeMs > cached.timestamp) {
104
+ stale.push(workspaceRoot);
105
+ }
106
+ }
107
+ catch {
108
+ // File doesn't exist anymore
109
+ stale.push(workspaceRoot);
110
+ }
111
+ }
112
+ return stale;
113
+ }
114
+ /**
115
+ * Normalizes a file path for cache keys.
116
+ */
117
+ normalizePath(filePath) {
118
+ return path.resolve(filePath);
119
+ }
120
+ }
121
+ /**
122
+ * Global singleton performance optimizer.
123
+ */
124
+ let globalOptimizer;
125
+ /**
126
+ * Gets the global performance optimizer instance.
127
+ */
128
+ export function getGlobalOptimizer() {
129
+ if (!globalOptimizer) {
130
+ globalOptimizer = new PerformanceOptimizer();
131
+ }
132
+ return globalOptimizer;
133
+ }
134
+ /**
135
+ * Resets the global optimizer (useful for testing).
136
+ */
137
+ export function resetGlobalOptimizer() {
138
+ globalOptimizer = undefined;
139
+ }
140
+ //# sourceMappingURL=performance-optimizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-optimizer.js","sourceRoot":"","sources":["../../src/services/performance-optimizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Model } from '../generated/ast.js';
2
+ /**
3
+ * Enriches relationships in the model by inferring relationship types
4
+ * from roles and arrow directions.
5
+ *
6
+ * This service walks the entire model structure and applies inference
7
+ * rules to relationships that don't have an explicit type.
8
+ *
9
+ * @param model - The root model to process
10
+ */
11
+ export declare function setInferredRelationshipTypes(model: Model): void;
@@ -0,0 +1,98 @@
1
+ import { isBoundedContext, isContextMap, isNamespaceDeclaration } from '../generated/ast.js';
2
+ /**
3
+ * Enriches relationships in the model by inferring relationship types
4
+ * from roles and arrow directions.
5
+ *
6
+ * This service walks the entire model structure and applies inference
7
+ * rules to relationships that don't have an explicit type.
8
+ *
9
+ * @param model - The root model to process
10
+ */
11
+ export function setInferredRelationshipTypes(model) {
12
+ walkStructureElements(model.children);
13
+ }
14
+ /**
15
+ * Recursively walks structure elements to find and enrich relationships.
16
+ *
17
+ * @param elements - Array of structure elements to process
18
+ * @param containerBc - Optional container bounded context (for nested contexts)
19
+ */
20
+ function walkStructureElements(elements = [], containerBc) {
21
+ for (const element of elements) {
22
+ if (isNamespaceDeclaration(element)) {
23
+ walkStructureElements(element.children, containerBc);
24
+ }
25
+ else if (isBoundedContext(element)) {
26
+ processContextRelationships(element);
27
+ }
28
+ else if (isContextMap(element)) {
29
+ processMapRelationships(element);
30
+ }
31
+ }
32
+ }
33
+ /**
34
+ * Processes relationships within a bounded context.
35
+ *
36
+ * @param context - The bounded context to process
37
+ */
38
+ function processContextRelationships(context) {
39
+ for (const rel of context.relationships) {
40
+ enrichRelationship(rel);
41
+ }
42
+ }
43
+ /**
44
+ * Processes relationships within a context map.
45
+ *
46
+ * @param map - The context map to process
47
+ */
48
+ function processMapRelationships(map) {
49
+ if (map.relationships) {
50
+ for (const rel of map.relationships) {
51
+ enrichRelationship(rel);
52
+ }
53
+ }
54
+ }
55
+ /**
56
+ * Enriches a single relationship by inferring its type if not explicitly set.
57
+ *
58
+ * @param rel - The relationship to enrich
59
+ */
60
+ function enrichRelationship(rel) {
61
+ if (!rel.type) {
62
+ rel.inferredType = inferRelationshipType(rel);
63
+ }
64
+ }
65
+ /**
66
+ * Infers relationship type from arrow direction and roles.
67
+ *
68
+ * Inference rules:
69
+ * - `><` → SeparateWays
70
+ * - `<->` with P roles → Partnership
71
+ * - `<->` with SK roles → SharedKernel
72
+ * - `->` or `<-` → UpstreamDownstream
73
+ *
74
+ * @param relationship - The relationship to analyze
75
+ * @returns The inferred type or undefined if no rule matches
76
+ */
77
+ function inferRelationshipType(relationship) {
78
+ const leftPatterns = (relationship.leftPatterns ?? []).map((r) => r.toUpperCase());
79
+ const rightPatterns = (relationship.rightPatterns ?? []).map((r) => r.toUpperCase());
80
+ if (relationship.arrow === '><') {
81
+ return 'SeparateWays';
82
+ }
83
+ if (relationship.arrow === '<->') {
84
+ const noPatterns = leftPatterns.length === 0 && rightPatterns.length === 0;
85
+ const bothPartners = leftPatterns.includes('P') && rightPatterns.includes('P');
86
+ if (noPatterns || bothPartners) {
87
+ return 'Partnership';
88
+ }
89
+ if (leftPatterns.includes('SK') && rightPatterns.includes('SK')) {
90
+ return 'SharedKernel';
91
+ }
92
+ }
93
+ if (relationship.arrow === '->' || relationship.arrow === '<-') {
94
+ return 'UpstreamDownstream';
95
+ }
96
+ return undefined;
97
+ }
98
+ //# sourceMappingURL=relationship-inference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationship-inference.js","sourceRoot":"","sources":["../../src/services/relationship-inference.ts"],"names":[],"mappings":"AAOA,OAAO,EACH,gBAAgB,EAChB,YAAY,EACZ,sBAAsB,EACzB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;GAQG;AACH,MAAM,UAAU,4BAA4B,CAAC,KAAY;IACrD,qBAAqB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,SAAS,qBAAqB,CAC1B,WAA+B,EAAE,EACjC,WAA4B;IAE5B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QACjC,IAAI,sBAAsB,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9B,qBAAqB,CAAC,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QACzD,CAAC;aAAM,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,2BAA2B,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;aAAM,IAAI,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,uBAAuB,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;IACL,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,2BAA2B,CAAC,OAAuB;IACxD,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QACtC,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,uBAAuB,CAAC,GAAe;IAC5C,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC;QACpB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC;YAClC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;IACL,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,GAAiB;IACzC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACZ,GAAG,CAAC,YAAY,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAClD,CAAC;AACL,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,qBAAqB,CAAC,YAA0B;IACrD,MAAM,YAAY,GAAG,CAAC,YAAY,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3F,MAAM,aAAa,GAAG,CAAC,YAAY,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAE7F,IAAI,YAAY,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAC9B,OAAO,cAAc,CAAC;IAC1B,CAAC;IAED,IAAI,YAAY,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC;QAC3E,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAE/E,IAAI,UAAU,IAAI,YAAY,EAAE,CAAC;YAC7B,OAAO,aAAa,CAAC;QACzB,CAAC;QAED,IAAI,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9D,OAAO,cAAc,CAAC;QAC1B,CAAC;IACL,CAAC;IAED,IAAI,YAAY,CAAC,KAAK,KAAK,IAAI,IAAI,YAAY,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAC7D,OAAO,oBAAoB,CAAC;IAChC,CAAC;IAED,OAAO,SAAS,CAAC;AACrB,CAAC"}