@domainlang/language 0.11.0 → 0.13.0

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 (116) hide show
  1. package/out/ast-augmentation.d.ts +7 -2
  2. package/out/diagram/context-map-diagram-generator.d.ts +72 -0
  3. package/out/diagram/context-map-diagram-generator.js +405 -0
  4. package/out/diagram/context-map-diagram-generator.js.map +1 -0
  5. package/out/diagram/context-map-layout-configurator.d.ts +15 -0
  6. package/out/diagram/context-map-layout-configurator.js +39 -0
  7. package/out/diagram/context-map-layout-configurator.js.map +1 -0
  8. package/out/diagram/elk-layout-factory.d.ts +43 -0
  9. package/out/diagram/elk-layout-factory.js +64 -0
  10. package/out/diagram/elk-layout-factory.js.map +1 -0
  11. package/out/domain-lang-module.d.ts +7 -0
  12. package/out/domain-lang-module.js +11 -2
  13. package/out/domain-lang-module.js.map +1 -1
  14. package/out/generated/ast.d.ts +323 -51
  15. package/out/generated/ast.js +194 -33
  16. package/out/generated/ast.js.map +1 -1
  17. package/out/generated/grammar.js +418 -172
  18. package/out/generated/grammar.js.map +1 -1
  19. package/out/index.d.ts +3 -0
  20. package/out/index.js +4 -0
  21. package/out/index.js.map +1 -1
  22. package/out/lsp/domain-lang-code-lens-provider.d.ts +8 -0
  23. package/out/lsp/domain-lang-code-lens-provider.js +48 -0
  24. package/out/lsp/domain-lang-code-lens-provider.js.map +1 -0
  25. package/out/lsp/domain-lang-completion.js +39 -15
  26. package/out/lsp/domain-lang-completion.js.map +1 -1
  27. package/out/lsp/domain-lang-document-symbol-provider.js +5 -5
  28. package/out/lsp/domain-lang-document-symbol-provider.js.map +1 -1
  29. package/out/lsp/domain-lang-formatter.js +32 -0
  30. package/out/lsp/domain-lang-formatter.js.map +1 -1
  31. package/out/lsp/domain-lang-index-manager.d.ts +2 -3
  32. package/out/lsp/domain-lang-index-manager.js +5 -8
  33. package/out/lsp/domain-lang-index-manager.js.map +1 -1
  34. package/out/lsp/domain-lang-workspace-manager.d.ts +1 -1
  35. package/out/lsp/domain-lang-workspace-manager.js +2 -26
  36. package/out/lsp/domain-lang-workspace-manager.js.map +1 -1
  37. package/out/lsp/explain.js +9 -3
  38. package/out/lsp/explain.js.map +1 -1
  39. package/out/lsp/hover/domain-lang-hover.js +13 -11
  40. package/out/lsp/hover/domain-lang-hover.js.map +1 -1
  41. package/out/lsp/hover/domain-lang-keywords.js +29 -26
  42. package/out/lsp/hover/domain-lang-keywords.js.map +1 -1
  43. package/out/lsp/tool-handlers.js +63 -57
  44. package/out/lsp/tool-handlers.js.map +1 -1
  45. package/out/sdk/ast-augmentation.d.ts +29 -21
  46. package/out/sdk/ast-augmentation.js +11 -7
  47. package/out/sdk/ast-augmentation.js.map +1 -1
  48. package/out/sdk/index.d.ts +2 -2
  49. package/out/sdk/index.js +1 -1
  50. package/out/sdk/index.js.map +1 -1
  51. package/out/sdk/loader-node.js +2 -2
  52. package/out/sdk/loader-node.js.map +1 -1
  53. package/out/sdk/patterns.d.ts +50 -61
  54. package/out/sdk/patterns.js +92 -62
  55. package/out/sdk/patterns.js.map +1 -1
  56. package/out/sdk/query.js +54 -43
  57. package/out/sdk/query.js.map +1 -1
  58. package/out/sdk/serializers.js +20 -7
  59. package/out/sdk/serializers.js.map +1 -1
  60. package/out/sdk/types.d.ts +87 -18
  61. package/out/sdk/types.js.map +1 -1
  62. package/out/sdk/validator.js +48 -64
  63. package/out/sdk/validator.js.map +1 -1
  64. package/out/services/performance-optimizer.d.ts +3 -3
  65. package/out/services/performance-optimizer.js +1 -3
  66. package/out/services/performance-optimizer.js.map +1 -1
  67. package/out/services/relationship-inference.d.ts +4 -4
  68. package/out/services/relationship-inference.js +34 -46
  69. package/out/services/relationship-inference.js.map +1 -1
  70. package/out/syntaxes/domain-lang.monarch.js +1 -1
  71. package/out/syntaxes/domain-lang.monarch.js.map +1 -1
  72. package/out/utils/import-utils.d.ts +6 -20
  73. package/out/utils/import-utils.js +3 -63
  74. package/out/utils/import-utils.js.map +1 -1
  75. package/out/validation/constants.d.ts +23 -6
  76. package/out/validation/constants.js +24 -7
  77. package/out/validation/constants.js.map +1 -1
  78. package/out/validation/maps.js +10 -4
  79. package/out/validation/maps.js.map +1 -1
  80. package/out/validation/relationships.d.ts +4 -8
  81. package/out/validation/relationships.js +96 -48
  82. package/out/validation/relationships.js.map +1 -1
  83. package/package.json +5 -2
  84. package/src/ast-augmentation.ts +7 -2
  85. package/src/diagram/context-map-diagram-generator.ts +513 -0
  86. package/src/diagram/context-map-layout-configurator.ts +43 -0
  87. package/src/diagram/elk-layout-factory.ts +83 -0
  88. package/src/domain-lang-module.ts +19 -2
  89. package/src/domain-lang.langium +62 -26
  90. package/src/generated/ast.ts +413 -63
  91. package/src/generated/grammar.ts +418 -172
  92. package/src/index.ts +5 -0
  93. package/src/lsp/domain-lang-code-lens-provider.ts +54 -0
  94. package/src/lsp/domain-lang-completion.ts +42 -15
  95. package/src/lsp/domain-lang-document-symbol-provider.ts +5 -5
  96. package/src/lsp/domain-lang-formatter.ts +34 -0
  97. package/src/lsp/domain-lang-index-manager.ts +6 -9
  98. package/src/lsp/domain-lang-workspace-manager.ts +3 -29
  99. package/src/lsp/explain.ts +10 -2
  100. package/src/lsp/hover/domain-lang-hover.ts +10 -8
  101. package/src/lsp/hover/domain-lang-keywords.ts +27 -24
  102. package/src/lsp/tool-handlers.ts +61 -47
  103. package/src/sdk/ast-augmentation.ts +30 -21
  104. package/src/sdk/index.ts +11 -1
  105. package/src/sdk/loader-node.ts +2 -2
  106. package/src/sdk/patterns.ts +114 -76
  107. package/src/sdk/query.ts +57 -48
  108. package/src/sdk/serializers.ts +20 -7
  109. package/src/sdk/types.ts +92 -17
  110. package/src/sdk/validator.ts +52 -69
  111. package/src/services/performance-optimizer.ts +4 -6
  112. package/src/services/relationship-inference.ts +43 -54
  113. package/src/utils/import-utils.ts +9 -74
  114. package/src/validation/constants.ts +32 -9
  115. package/src/validation/maps.ts +12 -4
  116. package/src/validation/relationships.ts +150 -71
@@ -1,6 +1,6 @@
1
1
  import type { ValidationAcceptor } from 'langium';
2
2
  import type { ContextMap, DomainMap, Relationship, BoundedContextRef } from '../generated/ast.js';
3
- import { isThisRef } from '../generated/ast.js';
3
+ import { isDirectionalRelationship, isSymmetricRelationship, isThisRef } from '../generated/ast.js';
4
4
  import { ValidationMessages, buildCodeDescription, IssueCodes } from './constants.js';
5
5
 
6
6
  /**
@@ -139,9 +139,17 @@ function getRefKey(ref: BoundedContextRef): string {
139
139
  function buildRelationshipKey(rel: Relationship): string {
140
140
  const left = getRefKey(rel.left);
141
141
  const right = getRefKey(rel.right);
142
- const leftPatterns = (rel.leftPatterns ?? []).slice().sort((a, b) => a.localeCompare(b)).join(',');
143
- const rightPatterns = (rel.rightPatterns ?? []).slice().sort((a, b) => a.localeCompare(b)).join(',');
144
- return `[${leftPatterns}]${left}${rel.arrow}[${rightPatterns}]${right}`;
142
+ const arrow = rel.arrow ?? '';
143
+
144
+ if (isDirectionalRelationship(rel)) {
145
+ const leftPatterns = rel.leftPatterns.map(p => p.$type).sort().join(',');
146
+ const rightPatterns = rel.rightPatterns.map(p => p.$type).sort().join(',');
147
+ return `[${leftPatterns}]${left}${arrow}[${rightPatterns}]${right}`;
148
+ }
149
+
150
+ // Symmetric relationship
151
+ const pattern = isSymmetricRelationship(rel) && rel.pattern ? rel.pattern.$type : '';
152
+ return `[${pattern}]${left}${arrow}${right}`;
145
153
  }
146
154
 
147
155
  /**
@@ -1,11 +1,17 @@
1
1
  import type { ValidationAcceptor } from 'langium';
2
- import type { Relationship, BoundedContextRef } from '../generated/ast.js';
3
- import { isThisRef } from '../generated/ast.js';
2
+ import type { BoundedContextRef, Relationship } from '../generated/ast.js';
3
+ import {
4
+ isThisRef,
5
+ isDirectionalRelationship,
6
+ isSymmetricRelationship,
7
+ isAntiCorruptionLayer,
8
+ isConformist,
9
+ isOpenHostService,
10
+ isSupplier,
11
+ isCustomer,
12
+ } from '../generated/ast.js';
4
13
  import { ValidationMessages, buildCodeDescription } from './constants.js';
5
14
 
6
- /**
7
- * Gets a display name for a BoundedContextRef (handles 'this' and regular refs).
8
- */
9
15
  function getContextName(ref: BoundedContextRef): string {
10
16
  if (isThisRef(ref)) {
11
17
  return 'this';
@@ -14,54 +20,19 @@ function getContextName(ref: BoundedContextRef): string {
14
20
  }
15
21
 
16
22
  /**
17
- * Validates that SharedKernel patterns use bidirectional relationships.
18
- * SharedKernel implies mutual dependency and shared code ownership.
19
- *
20
- * @param relationship - The relationship to validate
21
- * @param accept - The validation acceptor for reporting issues
22
- */
23
- function validateSharedKernelBidirectional(
24
- relationship: Relationship,
25
- accept: ValidationAcceptor
26
- ): void {
27
- // Check if SharedKernel pattern exists on either side
28
- const hasSharedKernelLeft = relationship.leftPatterns?.some(
29
- pattern => pattern === 'SK' || pattern === 'SharedKernel'
30
- );
31
- const hasSharedKernelRight = relationship.rightPatterns?.some(
32
- pattern => pattern === 'SK' || pattern === 'SharedKernel'
33
- );
34
-
35
- if ((hasSharedKernelLeft || hasSharedKernelRight) && relationship.arrow !== '<->') {
36
- const leftName = getContextName(relationship.left);
37
- const rightName = getContextName(relationship.right);
38
-
39
- accept('warning',
40
- ValidationMessages.SHARED_KERNEL_MUST_BE_BIDIRECTIONAL(leftName, rightName, relationship.arrow),
41
- { node: relationship, property: 'arrow', codeDescription: buildCodeDescription('language.md', 'integration-patterns') }
42
- );
43
- }
44
- }
45
-
46
- /**
47
- * Validates that Anti-Corruption Layer (ACL) is on the consuming side.
48
- * ACL protects downstream context from upstream changes.
49
- *
50
- * @param relationship - The relationship to validate
51
- * @param accept - The validation acceptor for reporting issues
23
+ * Validates that ACL is on the downstream (consuming) side.
24
+ * ACL on upstream side of -> is a warning. ACL on upstream side of <- is also a warning.
52
25
  */
53
26
  function validateACLPlacement(
54
27
  relationship: Relationship,
55
28
  accept: ValidationAcceptor
56
29
  ): void {
57
- const hasACLLeft = relationship.leftPatterns?.some(
58
- pattern => pattern === 'ACL' || pattern === 'AntiCorruptionLayer'
59
- );
60
- const hasACLRight = relationship.rightPatterns?.some(
61
- pattern => pattern === 'ACL' || pattern === 'AntiCorruptionLayer'
62
- );
30
+ if (!isDirectionalRelationship(relationship)) return;
31
+
32
+ const hasACLLeft = relationship.leftPatterns.some(isAntiCorruptionLayer);
33
+ const hasACLRight = relationship.rightPatterns.some(isAntiCorruptionLayer);
63
34
 
64
- // ACL on left side with -> arrow means upstream has ACL (incorrect)
35
+ // For ->, left is upstream. ACL on upstream side is wrong.
65
36
  if (hasACLLeft && relationship.arrow === '->') {
66
37
  const leftName = getContextName(relationship.left);
67
38
  accept('warning',
@@ -70,7 +41,7 @@ function validateACLPlacement(
70
41
  );
71
42
  }
72
43
 
73
- // ACL on right side with <- arrow means upstream has ACL (incorrect)
44
+ // For <-, right is upstream. ACL on upstream side is wrong.
74
45
  if (hasACLRight && relationship.arrow === '<-') {
75
46
  const rightName = getContextName(relationship.right);
76
47
  accept('warning',
@@ -81,24 +52,17 @@ function validateACLPlacement(
81
52
  }
82
53
 
83
54
  /**
84
- * Validates that Conformist pattern is on the consuming side.
85
- * Conformist means accepting upstream model without translation.
86
- *
87
- * @param relationship - The relationship to validate
88
- * @param accept - The validation acceptor for reporting issues
55
+ * Validates that CF is on the downstream (consuming) side.
89
56
  */
90
57
  function validateConformistPlacement(
91
58
  relationship: Relationship,
92
59
  accept: ValidationAcceptor
93
60
  ): void {
94
- const hasCFLeft = relationship.leftPatterns?.some(
95
- pattern => pattern === 'CF' || pattern === 'Conformist'
96
- );
97
- const hasCFRight = relationship.rightPatterns?.some(
98
- pattern => pattern === 'CF' || pattern === 'Conformist'
99
- );
61
+ if (!isDirectionalRelationship(relationship)) return;
62
+
63
+ const hasCFLeft = relationship.leftPatterns.some(isConformist);
64
+ const hasCFRight = relationship.rightPatterns.some(isConformist);
100
65
 
101
- // CF on left side with -> arrow means upstream is conformist (incorrect)
102
66
  if (hasCFLeft && relationship.arrow === '->') {
103
67
  const leftName = getContextName(relationship.left);
104
68
  accept('warning',
@@ -107,7 +71,6 @@ function validateConformistPlacement(
107
71
  );
108
72
  }
109
73
 
110
- // CF on right side with <- arrow means upstream is conformist (incorrect)
111
74
  if (hasCFRight && relationship.arrow === '<-') {
112
75
  const rightName = getContextName(relationship.right);
113
76
  accept('warning',
@@ -118,18 +81,107 @@ function validateConformistPlacement(
118
81
  }
119
82
 
120
83
  /**
121
- * Validates that relationships don't have too many integration patterns.
122
- * More than 3 patterns on one side suggests syntax confusion.
123
- *
124
- * @param relationship - The relationship to validate
125
- * @param accept - The validation acceptor for reporting issues
84
+ * Validates that OHS is on the upstream (providing) side.
85
+ */
86
+ function validateOHSPlacement(
87
+ relationship: Relationship,
88
+ accept: ValidationAcceptor
89
+ ): void {
90
+ if (!isDirectionalRelationship(relationship)) return;
91
+
92
+ // For ->, right is downstream. OHS on downstream side is wrong.
93
+ const hasOHSRight = relationship.rightPatterns.some(isOpenHostService);
94
+ if (hasOHSRight && relationship.arrow === '->') {
95
+ const rightName = getContextName(relationship.right);
96
+ accept('warning',
97
+ ValidationMessages.OHS_ON_WRONG_SIDE(rightName, 'right'),
98
+ { node: relationship, property: 'rightPatterns', codeDescription: buildCodeDescription('language.md', 'integration-patterns') }
99
+ );
100
+ }
101
+
102
+ // For <-, left is downstream. OHS on downstream side is wrong.
103
+ const hasOHSLeft = relationship.leftPatterns.some(isOpenHostService);
104
+ if (hasOHSLeft && relationship.arrow === '<-') {
105
+ const leftName = getContextName(relationship.left);
106
+ accept('warning',
107
+ ValidationMessages.OHS_ON_WRONG_SIDE(leftName, 'left'),
108
+ { node: relationship, property: 'leftPatterns', codeDescription: buildCodeDescription('language.md', 'integration-patterns') }
109
+ );
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Validates that Supplier is on the upstream side and Customer is on the downstream side.
115
+ * These are errors, not warnings — S/C have fixed placement.
116
+ */
117
+ function validateCustomerSupplierPlacement(
118
+ relationship: Relationship,
119
+ accept: ValidationAcceptor
120
+ ): void {
121
+ if (!isDirectionalRelationship(relationship)) return;
122
+
123
+ // For ->, left is upstream, right is downstream
124
+ // Supplier must be upstream, Customer must be downstream
125
+ if (relationship.arrow === '->') {
126
+ if (relationship.rightPatterns.some(isSupplier)) {
127
+ accept('error',
128
+ ValidationMessages.SUPPLIER_ON_WRONG_SIDE(getContextName(relationship.right), 'right'),
129
+ { node: relationship, property: 'rightPatterns', codeDescription: buildCodeDescription('language.md', 'integration-patterns') }
130
+ );
131
+ }
132
+ if (relationship.leftPatterns.some(isCustomer)) {
133
+ accept('error',
134
+ ValidationMessages.CUSTOMER_ON_WRONG_SIDE(getContextName(relationship.left), 'left'),
135
+ { node: relationship, property: 'leftPatterns', codeDescription: buildCodeDescription('language.md', 'integration-patterns') }
136
+ );
137
+ }
138
+ }
139
+
140
+ // For <-, right is upstream, left is downstream
141
+ if (relationship.arrow === '<-') {
142
+ if (relationship.leftPatterns.some(isSupplier)) {
143
+ accept('error',
144
+ ValidationMessages.SUPPLIER_ON_WRONG_SIDE(getContextName(relationship.left), 'left'),
145
+ { node: relationship, property: 'leftPatterns', codeDescription: buildCodeDescription('language.md', 'integration-patterns') }
146
+ );
147
+ }
148
+ if (relationship.rightPatterns.some(isCustomer)) {
149
+ accept('error',
150
+ ValidationMessages.CUSTOMER_ON_WRONG_SIDE(getContextName(relationship.right), 'right'),
151
+ { node: relationship, property: 'rightPatterns', codeDescription: buildCodeDescription('language.md', 'integration-patterns') }
152
+ );
153
+ }
154
+ }
155
+
156
+ // <-> is bidirectional — Customer/Supplier is inherently directional and must not appear on a <-> arrow
157
+ if (relationship.arrow === '<->') {
158
+ const allPatterns = [...relationship.leftPatterns, ...relationship.rightPatterns];
159
+ if (allPatterns.some(isSupplier)) {
160
+ accept('error',
161
+ 'Supplier [S] cannot be used on a bidirectional (<->) relationship — Customer/Supplier is inherently directional.',
162
+ { node: relationship, property: relationship.leftPatterns.some(isSupplier) ? 'leftPatterns' : 'rightPatterns', codeDescription: buildCodeDescription('language.md', 'integration-patterns') }
163
+ );
164
+ }
165
+ if (allPatterns.some(isCustomer)) {
166
+ accept('error',
167
+ 'Customer [C] cannot be used on a bidirectional (<->) relationship — Customer/Supplier is inherently directional.',
168
+ { node: relationship, property: relationship.leftPatterns.some(isCustomer) ? 'leftPatterns' : 'rightPatterns', codeDescription: buildCodeDescription('language.md', 'integration-patterns') }
169
+ );
170
+ }
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Validates pattern count per side (info if > 3).
126
176
  */
127
177
  function validatePatternCount(
128
178
  relationship: Relationship,
129
179
  accept: ValidationAcceptor
130
180
  ): void {
131
- const leftCount = relationship.leftPatterns?.length ?? 0;
132
- const rightCount = relationship.rightPatterns?.length ?? 0;
181
+ if (!isDirectionalRelationship(relationship)) return;
182
+
183
+ const leftCount = relationship.leftPatterns.length;
184
+ const rightCount = relationship.rightPatterns.length;
133
185
 
134
186
  if (leftCount > 3) {
135
187
  accept('info',
@@ -146,9 +198,36 @@ function validatePatternCount(
146
198
  }
147
199
  }
148
200
 
149
- export const relationshipChecks = [
150
- validateSharedKernelBidirectional,
201
+ /**
202
+ * Validates that symmetric relationships with self-reference produce a warning.
203
+ */
204
+ function validateSelfSymmetric(
205
+ relationship: Relationship,
206
+ accept: ValidationAcceptor
207
+ ): void {
208
+ if (!isSymmetricRelationship(relationship)) return;
209
+
210
+ const leftName = getContextName(relationship.left);
211
+ const rightName = getContextName(relationship.right);
212
+
213
+ if (leftName === rightName) {
214
+ accept('warning',
215
+ ValidationMessages.SELF_SYMMETRIC_RELATIONSHIP(leftName),
216
+ { node: relationship, codeDescription: buildCodeDescription('language.md', 'integration-patterns') }
217
+ );
218
+ }
219
+ }
220
+
221
+ /**
222
+ * All relationship validation checks.
223
+ * Each function receives a Relationship (DirectionalRelationship | SymmetricRelationship)
224
+ * and guards internally for the correct subtype.
225
+ */
226
+ export const relationshipChecks: Array<(relationship: Relationship, accept: ValidationAcceptor) => void> = [
151
227
  validateACLPlacement,
152
228
  validateConformistPlacement,
153
- validatePatternCount
229
+ validateOHSPlacement,
230
+ validateCustomerSupplierPlacement,
231
+ validatePatternCount,
232
+ validateSelfSymmetric,
154
233
  ];