@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,7 +1,7 @@
1
1
  // Monarch syntax highlighting for the domain-lang language.
2
2
  export default {
3
3
  keywords: [
4
- 'ACL','AntiCorruptionLayer','BBoM','BigBallOfMud','BoundedContext','CF','Classification','Conformist','ContextMap','CustomerSupplier','Decision','Domain','DomainMap','Import','Metadata','Namespace','OHS','OpenHostService','P','PL','Partnership','Policy','PublishedLanguage','Rule','SK','SeparateWays','SharedKernel','Team','Term','UpstreamDownstream','aka','archetype','as','bc','businessModel','by','classification','cmap','contains','decision','decisions','description','dmap','dom','evolution','examples','for','glossary','import','in','integrations','is','meta','metadata','ns','policy','relationships','rule','rules','synonyms','team','term','terminology','this','type','vision'
4
+ 'ACL','AntiCorruptionLayer','BBoM','BigBallOfMud','BoundedContext','CF','Classification','Conformist','ContextMap','CustomerSupplier','Decision','Domain','DomainMap','Import','Metadata','Namespace','OHS','OpenHostService','P','PL','Partnership','Policy','PublishedLanguage','Rule','SK','SeparateWays','SharedKernel','Team','Term','UpstreamDownstream','aka','archetype','as','bc','businessModel','by','classification','cmap','contains','decision','decisions','description','dmap','dom','evolution','examples','for','from','glossary','import','in','integrations','integrity','is','meta','metadata','ns','policy','relationships','rule','rules','synonyms','team','term','terminology','this','type','vision'
5
5
  ],
6
6
  operators: [
7
7
  ',','->','.',':','<-','<->','=','><'
@@ -1,66 +1,129 @@
1
+ import fs from 'node:fs/promises';
1
2
  import path from 'node:path';
2
3
  import { URI, type LangiumDocument, type LangiumDocuments } from 'langium';
3
4
  import type { Model } from '../generated/ast.js';
5
+ import { GitUrlParser } from '../services/git-url-resolver.js';
4
6
  import type { GitUrlResolver } from '../services/git-url-resolver.js';
5
7
  import { WorkspaceManager } from '../services/workspace-manager.js';
6
- import { ImportResolver } from '../services/import-resolver.js';
7
- import type { DomainLangServices } from '../domain-lang-module.js';
8
8
 
9
- /**
10
- * Lazily initialized workspace manager for standalone (non-LSP) usage.
11
- * Used by import graph building when services aren't available from DI.
12
- */
13
- let standaloneWorkspaceManager: WorkspaceManager | undefined;
14
- let standaloneImportResolver: ImportResolver | undefined;
15
- let lastInitializedDir: string | undefined;
9
+ // Singleton workspace manager instance
10
+ let workspaceManager: WorkspaceManager | undefined;
16
11
 
17
12
  /**
18
- * Gets or creates a standalone import resolver for non-LSP contexts.
19
- * Creates its own WorkspaceManager if not previously initialized for this directory.
20
- *
21
- * NOTE: In LSP contexts, prefer using services.imports.ImportResolver directly.
22
- * This function exists for utilities that don't have access to the service container.
23
- *
13
+ * Gets or creates the global workspace manager instance.
14
+ *
24
15
  * @param startDir - Directory to start workspace search from
25
- * @returns Promise resolving to the import resolver
16
+ * @returns Promise resolving to the workspace manager
26
17
  */
27
- async function getStandaloneImportResolver(startDir: string): Promise<ImportResolver> {
28
- // Re-initialize if directory changed (workspace boundary)
29
- if (lastInitializedDir !== startDir || !standaloneImportResolver) {
30
- standaloneWorkspaceManager = new WorkspaceManager({ autoResolve: false, allowNetwork: false });
18
+ async function getWorkspaceManager(startDir: string): Promise<WorkspaceManager> {
19
+ if (!workspaceManager) {
20
+ workspaceManager = new WorkspaceManager();
21
+ const root = await findWorkspaceRoot(startDir);
31
22
  try {
32
- await standaloneWorkspaceManager.initialize(startDir);
23
+ await workspaceManager.initialize(root);
33
24
  } catch (error) {
34
25
  console.warn(`Failed to initialize workspace: ${error instanceof Error ? error.message : String(error)}`);
26
+ // Continue without workspace - local imports will still work
35
27
  }
36
- const services = {
37
- imports: { WorkspaceManager: standaloneWorkspaceManager }
38
- } as DomainLangServices;
39
- standaloneImportResolver = new ImportResolver(services);
40
- lastInitializedDir = startDir;
41
28
  }
42
- return standaloneImportResolver;
29
+ return workspaceManager;
43
30
  }
44
31
 
45
32
  /**
46
- * Gets the git URL resolver from a workspace manager.
47
- *
33
+ * Gets the git URL resolver from the workspace manager.
34
+ *
48
35
  * @param startDir - Directory to start workspace search from
49
36
  * @returns Promise resolving to the git URL resolver
50
37
  */
51
38
  async function getGitResolver(startDir: string): Promise<GitUrlResolver> {
52
- const workspaceManager = new WorkspaceManager({ autoResolve: false, allowNetwork: false });
53
- await workspaceManager.initialize(startDir);
54
- return workspaceManager.getGitResolver();
39
+ const manager = await getWorkspaceManager(startDir);
40
+ return await manager.getGitResolver();
41
+ }
42
+
43
+ /**
44
+ * Ensures a file path has the .dlang extension.
45
+ *
46
+ * @param filePath - The raw file path
47
+ * @returns Normalized path with .dlang extension
48
+ * @throws {Error} If path has an invalid extension
49
+ */
50
+ function ensureDlangExtension(filePath: string): string {
51
+ const ext = path.extname(filePath);
52
+
53
+ if (!ext) {
54
+ return `${filePath}.dlang`;
55
+ }
56
+
57
+ if (ext !== '.dlang') {
58
+ throw new Error(
59
+ `Invalid file extension: ${ext}. Expected .dlang for file: ${filePath}`
60
+ );
61
+ }
62
+
63
+ return filePath;
64
+ }
65
+
66
+ /**
67
+ * Resolves workspace-relative paths (starting with ~/).
68
+ *
69
+ * @param importPath - Import path that may start with ~/
70
+ * @param workspaceRoot - The workspace root directory
71
+ * @returns Resolved absolute path
72
+ */
73
+ function resolveWorkspacePath(importPath: string, workspaceRoot: string): string {
74
+ if (importPath.startsWith('~/')) {
75
+ return path.join(workspaceRoot, importPath.slice(2));
76
+ }
77
+ return importPath;
78
+ }
79
+
80
+ /**
81
+ * Finds the workspace root by looking for common workspace indicators.
82
+ *
83
+ * Searches upward from the document's directory looking for:
84
+ * - dlang.toml
85
+ * - .git directory
86
+ * - package.json with dlang configuration
87
+ *
88
+ * @param startDir - Directory to start searching from
89
+ * @returns Workspace root path or the start directory if not found
90
+ */
91
+ async function findWorkspaceRoot(startDir: string): Promise<string> {
92
+ let currentDir = startDir;
93
+ const root = path.parse(currentDir).root;
94
+
95
+ while (currentDir !== root) {
96
+ // Check for workspace indicators
97
+ const indicators = ['dlang.toml', '.git', 'package.json'];
98
+
99
+ for (const indicator of indicators) {
100
+ const indicatorPath = path.join(currentDir, indicator);
101
+ try {
102
+ await fs.access(indicatorPath);
103
+ return currentDir; // Found workspace root
104
+ } catch {
105
+ // Continue searching
106
+ }
107
+ }
108
+
109
+ // Move up one directory
110
+ const parentDir = path.dirname(currentDir);
111
+ if (parentDir === currentDir) break; // Reached root
112
+ currentDir = parentDir;
113
+ }
114
+
115
+ // Default to start directory if no workspace root found
116
+ return startDir;
55
117
  }
56
118
 
57
119
  /**
58
120
  * Resolves an import path to an absolute file URI.
59
121
  *
60
- * Delegates to ImportResolver which implements PRS-010 semantics:
61
- * - File imports (with .dlang extension): Direct file access
62
- * - Module imports (no extension): Requires model.yaml in directory
63
- * - External dependencies: Resolved via manifest and lock file
122
+ * Supports:
123
+ * - Local relative paths: ./file.dlang, ../other/file.dlang
124
+ * - Workspace-relative paths: ~/contexts/sales.dlang
125
+ * - Git URLs: gh:owner/repo@v1.0.0/file.dlang
126
+ * - Full URLs: https://github.com/owner/repo/blob/v1.0.0/file.dlang
64
127
  *
65
128
  * @param importingDoc - The document containing the import statement
66
129
  * @param rawImportPath - The raw import path from the import statement
@@ -72,8 +135,65 @@ export async function resolveImportPath(
72
135
  rawImportPath: string
73
136
  ): Promise<URI> {
74
137
  const baseDir = path.dirname(importingDoc.uri.fsPath);
75
- const resolver = await getStandaloneImportResolver(baseDir);
76
- return resolver.resolveFrom(baseDir, rawImportPath);
138
+
139
+ // Handle manifest dependency aliases (friendly names)
140
+ const manager = await getWorkspaceManager(baseDir);
141
+ let gitResolver: GitUrlResolver | undefined;
142
+
143
+ try {
144
+ const manifestImport = await manager.resolveDependencyImport(rawImportPath);
145
+ if (manifestImport) {
146
+ gitResolver = await manager.getGitResolver();
147
+ return await gitResolver.resolve(manifestImport);
148
+ }
149
+ } catch {
150
+ // Ignore manifest resolution issues; fall back to other strategies
151
+ }
152
+
153
+ // Handle git URLs (shorthand or full)
154
+ if (GitUrlParser.isGitUrl(rawImportPath)) {
155
+ gitResolver = gitResolver ?? await manager.getGitResolver();
156
+ return await gitResolver.resolve(rawImportPath);
157
+ }
158
+
159
+ // Handle workspace-relative paths (~/)
160
+ let resolvedPath = rawImportPath;
161
+
162
+ if (rawImportPath.startsWith('~/')) {
163
+ const workspaceRoot = await findWorkspaceRoot(baseDir);
164
+ resolvedPath = resolveWorkspacePath(rawImportPath, workspaceRoot);
165
+ } else if (!path.isAbsolute(rawImportPath)) {
166
+ // Handle relative paths
167
+ resolvedPath = path.resolve(baseDir, rawImportPath);
168
+ }
169
+
170
+ // Ensure .dlang extension
171
+ const normalized = ensureDlangExtension(resolvedPath);
172
+
173
+ // Verify file exists
174
+ try {
175
+ await fs.access(normalized);
176
+ } catch {
177
+ throw new Error(
178
+ `Import file not found: ${rawImportPath} (resolved to ${normalized})`
179
+ );
180
+ }
181
+
182
+ return URI.file(normalized);
183
+ }
184
+
185
+ /**
186
+ * Legacy function for backward compatibility.
187
+ * Use resolveImportPath instead.
188
+ *
189
+ * @deprecated Use resolveImportPath which supports git URLs and workspace paths
190
+ */
191
+ export async function resolveLocalImportPath(
192
+ importingDoc: LangiumDocument,
193
+ rawImportPath: string
194
+ ): Promise<string> {
195
+ const uri = await resolveImportPath(importingDoc, rawImportPath);
196
+ return uri.fsPath;
77
197
  }
78
198
 
79
199
  /**
@@ -150,3 +270,5 @@ export async function clearGitCache(startDir: string = process.cwd()): Promise<v
150
270
  const resolver = await getGitResolver(startDir);
151
271
  return await resolver.clearCache();
152
272
  }
273
+
274
+
@@ -13,58 +13,6 @@
13
13
 
14
14
  import type { CodeDescription } from 'vscode-languageserver-types';
15
15
 
16
- // ============================================================================
17
- // Issue Codes for Code Actions
18
- // ============================================================================
19
-
20
- /**
21
- * Diagnostic codes used to identify validation issues.
22
- * Code actions match on these codes to provide quick fixes.
23
- *
24
- * Naming convention: CATEGORY_SPECIFIC_ISSUE
25
- */
26
- export const IssueCodes = {
27
- // Import & Dependency Issues
28
- ImportMissingUri: 'import-missing-uri',
29
- ImportRequiresManifest: 'import-requires-manifest',
30
- ImportNotInManifest: 'import-not-in-manifest',
31
- ImportNotInstalled: 'import-not-installed',
32
- ImportConflictingSourcePath: 'import-conflicting-source-path',
33
- ImportMissingSourceOrPath: 'import-missing-source-or-path',
34
- ImportMissingRef: 'import-missing-ref',
35
- ImportAbsolutePath: 'import-absolute-path',
36
- ImportEscapesWorkspace: 'import-escapes-workspace',
37
-
38
- // Domain Issues
39
- DomainNoVision: 'domain-no-vision',
40
- DomainCircularHierarchy: 'domain-circular-hierarchy',
41
-
42
- // Bounded Context Issues
43
- BoundedContextNoDescription: 'bounded-context-no-description',
44
- BoundedContextNoDomain: 'bounded-context-no-domain',
45
- BoundedContextClassificationConflict: 'bounded-context-classification-conflict',
46
- BoundedContextTeamConflict: 'bounded-context-team-conflict',
47
-
48
- // Integration Pattern Issues
49
- SharedKernelNotBidirectional: 'shared-kernel-not-bidirectional',
50
- AclOnWrongSide: 'acl-on-wrong-side',
51
- ConformistOnWrongSide: 'conformist-on-wrong-side',
52
- TooManyPatterns: 'too-many-patterns',
53
-
54
- // Context/Domain Map Issues
55
- ContextMapNoContexts: 'context-map-no-contexts',
56
- ContextMapNoRelationships: 'context-map-no-relationships',
57
- DomainMapNoDomains: 'domain-map-no-domains',
58
-
59
- // Metadata Issues
60
- MetadataMissingName: 'metadata-missing-name',
61
-
62
- // General Issues
63
- DuplicateElement: 'duplicate-element'
64
- } as const;
65
-
66
- export type IssueCode = typeof IssueCodes[keyof typeof IssueCodes];
67
-
68
16
  // ============================================================================
69
17
  // Documentation Link Utilities
70
18
  // ============================================================================
@@ -101,13 +49,6 @@ export const ValidationMessages = {
101
49
  DOMAIN_NO_VISION: (name: string) =>
102
50
  `Domain '${name}' is missing a vision statement.`,
103
51
 
104
- /**
105
- * Error message when a circular domain hierarchy is detected.
106
- * @param cycle - Array of domain names forming the cycle
107
- */
108
- DOMAIN_CIRCULAR_HIERARCHY: (cycle: string[]) =>
109
- `Circular domain hierarchy detected: ${cycle.join(' → ')}.`,
110
-
111
52
  /**
112
53
  * Warning message when a bounded context lacks a description.
113
54
  * @param name - The name of the bounded context
@@ -179,126 +120,5 @@ export const ValidationMessages = {
179
120
  * Suggests possible syntax confusion.
180
121
  */
181
122
  TOO_MANY_PATTERNS: (count: number, side: 'left' | 'right') =>
182
- `Too many integration patterns (${count}) on ${side} side. Typically use 1-2 patterns per side.`,
183
-
184
- // ========================================================================
185
- // Import & Dependency Validation (PRS-010 Phase 8)
186
- // ========================================================================
187
-
188
- /**
189
- * Error when import statement has no URI.
190
- */
191
- IMPORT_MISSING_URI: () =>
192
- `Import statement must have a URI. Use: import "package" or import "./local-path"`,
193
-
194
- /**
195
- * Error when external dependency requires model.yaml but none exists.
196
- * @param specifier - The import specifier (e.g., "core", "domainlang/patterns")
197
- */
198
- IMPORT_REQUIRES_MANIFEST: (specifier: string) =>
199
- `External dependency '${specifier}' requires model.yaml.\n` +
200
- `Hint: Create model.yaml and add the dependency:\n` +
201
- ` dependencies:\n` +
202
- ` ${specifier}:\n` +
203
- ` ref: v1.0.0`,
204
-
205
- /**
206
- * Error when import specifier not found in manifest dependencies.
207
- * @param alias - The dependency alias/specifier
208
- */
209
- IMPORT_NOT_IN_MANIFEST: (alias: string) =>
210
- `Import '${alias}' not found in model.yaml dependencies.\n` +
211
- `Hint: Run 'dlang add ${alias} <source>@<ref>' to add it, or manually add to model.yaml:\n` +
212
- ` dependencies:\n` +
213
- ` ${alias}:\n` +
214
- ` ref: v1.0.0`,
215
-
216
- /**
217
- * Error when dependency not installed (no lock file entry).
218
- * @param alias - The dependency alias
219
- */
220
- IMPORT_NOT_INSTALLED: (alias: string) =>
221
- `Dependency '${alias}' not installed.\n` +
222
- `Hint: Run 'dlang install' to fetch dependencies and generate model.lock.`,
223
-
224
- /**
225
- * Error when dependency has conflicting source and path definitions.
226
- * @param alias - The dependency alias
227
- */
228
- IMPORT_CONFLICTING_SOURCE_PATH: (alias: string) =>
229
- `Dependency '${alias}' cannot define both 'source' and 'path' in model.yaml.\n` +
230
- `Hint: Use 'source' for git-based packages or 'path' for local workspace packages.`,
231
-
232
- /**
233
- * Error when dependency is missing both source and path.
234
- * @param alias - The dependency alias
235
- */
236
- IMPORT_MISSING_SOURCE_OR_PATH: (alias: string) =>
237
- `Dependency '${alias}' must define either 'source' or 'path' in model.yaml.\n` +
238
- `Hint: Add 'source: owner/repo' for git packages, or 'path: ./local/path' for local packages.`,
239
-
240
- /**
241
- * Error when git dependency is missing ref (tag, branch, or commit).
242
- * @param alias - The dependency alias
243
- */
244
- IMPORT_MISSING_REF: (alias: string) =>
245
- `Dependency '${alias}' must specify a git ref in model.yaml.\n` +
246
- `Hint: Add a git ref: 'ref: v1.0.0' (tag), 'ref: main' (branch), or a commit SHA.`,
247
-
248
- /**
249
- * Error when local path uses absolute path.
250
- * @param alias - The dependency alias
251
- * @param absolutePath - The absolute path that was specified
252
- */
253
- IMPORT_ABSOLUTE_PATH: (alias: string, absolutePath: string) =>
254
- `Local path dependency '${alias}' cannot use absolute path '${absolutePath}'.\n` +
255
- `Hint: Use a relative path from the workspace root, e.g., 'path: ./packages/shared'.`,
256
-
257
- /**
258
- * Error when local path escapes workspace boundary.
259
- * @param alias - The dependency alias
260
- */
261
- IMPORT_ESCAPES_WORKSPACE: (alias: string) =>
262
- `Local path dependency '${alias}' escapes workspace boundary.\n` +
263
- `Hint: Local dependencies must be within the workspace. Consider moving the dependency or using a git-based source.`,
264
-
265
- // ========================================================================
266
- // Context Map & Domain Map Validation
267
- // ========================================================================
268
-
269
- /**
270
- * Warning when context map contains no bounded contexts.
271
- * @param name - The context map name
272
- */
273
- CONTEXT_MAP_NO_CONTEXTS: (name: string) =>
274
- `Context Map '${name}' contains no bounded contexts.\n` +
275
- `Hint: Use 'contains ContextA, ContextB' to specify which contexts are in the map.`,
276
-
277
- /**
278
- * Info when context map has multiple contexts but no relationships.
279
- * @param name - The context map name
280
- * @param count - Number of contexts
281
- */
282
- CONTEXT_MAP_NO_RELATIONSHIPS: (name: string, count: number) =>
283
- `Context Map '${name}' contains ${count} contexts but no documented relationships.\n` +
284
- `Hint: Add relationships to show how contexts integrate (e.g., '[OHS] A -> [CF] B').`,
285
-
286
- /**
287
- * Warning when domain map contains no domains.
288
- * @param name - The domain map name
289
- */
290
- DOMAIN_MAP_NO_DOMAINS: (name: string) =>
291
- `Domain Map '${name}' contains no domains.\n` +
292
- `Hint: Use 'contains DomainA, DomainB' to specify which domains are in the map.`,
293
-
294
- // ========================================================================
295
- // Metadata Validation
296
- // ========================================================================
297
-
298
- /**
299
- * Error when metadata is missing a name.
300
- */
301
- METADATA_MISSING_NAME: () =>
302
- `Metadata must have a name.\n` +
303
- `Hint: Define metadata with: Metadata MyMetadata { ... }`
123
+ `Too many integration patterns (${count}) on ${side} side. Typically use 1-2 patterns per side.`
304
124
  } as const;
@@ -21,57 +21,4 @@ function validateDomainHasVision(
21
21
  }
22
22
  }
23
23
 
24
- /**
25
- * Validates that a domain hierarchy does not contain circular references.
26
- *
27
- * The `Domain A in B` syntax expresses subdomain containment.
28
- * Circular containment (A in B, B in C, C in A) is semantically invalid
29
- * because it violates the fundamental concept of domain decomposition.
30
- *
31
- * @param domain - The domain to validate
32
- * @param accept - The validation acceptor for reporting issues
33
- */
34
- function validateNoCyclicDomainHierarchy(
35
- domain: Domain,
36
- accept: ValidationAcceptor
37
- ): void {
38
- // Only check if this domain has a parent
39
- if (!domain.parent?.ref) {
40
- return;
41
- }
42
-
43
- const visited = new Set<Domain>();
44
- const path: string[] = [domain.name];
45
- let current: Domain | undefined = domain.parent.ref;
46
-
47
- while (current) {
48
- // Check if we've encountered this domain before (cycle detected)
49
- if (visited.has(current)) {
50
- // We found a cycle - report it
51
- path.push(current.name);
52
- accept('error', ValidationMessages.DOMAIN_CIRCULAR_HIERARCHY(path), {
53
- node: domain,
54
- property: 'parent',
55
- codeDescription: buildCodeDescription('language.md', 'domain-hierarchy')
56
- });
57
- return;
58
- }
59
-
60
- // Check if we've looped back to the starting domain
61
- if (current === domain) {
62
- path.push(domain.name);
63
- accept('error', ValidationMessages.DOMAIN_CIRCULAR_HIERARCHY(path), {
64
- node: domain,
65
- property: 'parent',
66
- codeDescription: buildCodeDescription('language.md', 'domain-hierarchy')
67
- });
68
- return;
69
- }
70
-
71
- visited.add(current);
72
- path.push(current.name);
73
- current = current.parent?.ref;
74
- }
75
- }
76
-
77
- export const domainChecks = [validateDomainHasVision, validateNoCyclicDomainHierarchy];
24
+ export const domainChecks = [validateDomainHasVision];