@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 +1 @@
1
- {"version":3,"file":"relationships.js","sourceRoot":"","sources":["../../src/validation/relationships.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relationships.js","sourceRoot":"","sources":["../../src/validation/relationships.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@domainlang/language",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "displayName": "DomainLang Language",
5
5
  "description": "Core language library for DomainLang - parse, validate, and query Domain-Driven Design models programmatically",
6
6
  "author": "larsbaunwall",
@@ -85,9 +85,12 @@
85
85
  "test:coverage": "vitest run --coverage"
86
86
  },
87
87
  "dependencies": {
88
+ "elkjs": "^0.8.2",
88
89
  "langium": "~4.2.0",
90
+ "langium-sprotty": "~4.2.0",
89
91
  "monaco-editor": "0.55.1",
90
- "vite": "6.4.1",
92
+ "sprotty-elk": "~1.4.0",
93
+ "sprotty-protocol": "~1.4.0",
91
94
  "yaml": "^2.5.0"
92
95
  },
93
96
  "devDependencies": {
@@ -1,5 +1,10 @@
1
1
  declare module './generated/ast.js' {
2
- interface Relationship {
3
- inferredType?: string;
2
+ interface DirectionalRelationship {
3
+ /** SDK-inferred relationship kind based on patterns and arrow */
4
+ inferredKind?: string;
5
+ }
6
+ interface SymmetricRelationship {
7
+ /** SDK-inferred relationship kind from pattern or >< arrow */
8
+ inferredKind?: string;
4
9
  }
5
10
  }
@@ -0,0 +1,513 @@
1
+ import type { LangiumDocument } from 'langium';
2
+ import type { SGraph, SModelElement, SModelRoot, SEdge, SNode } from 'sprotty-protocol';
3
+ import { LangiumDiagramGenerator, type GeneratorContext } from 'langium-sprotty';
4
+ import { fromDocument } from '../sdk/query.js';
5
+ import type { Query, RelationshipView } from '../sdk/types.js';
6
+ import { isBigBallOfMud } from '../generated/ast.js';
7
+ import type { BoundedContext, ContextMap, Model, Relationship, SidePattern } from '../generated/ast.js';
8
+
9
+ /** Ellipse sizing for bounded context nodes — sized for long names like "CustomerManagementContext" */
10
+ const NODE_WIDTH = 280;
11
+ const NODE_HEIGHT = 100;
12
+
13
+ /**
14
+ * Maps long-form DomainLang integration pattern keywords to their standard
15
+ * DDD abbreviations for display in U/D badges.
16
+ */
17
+ const PATTERN_ABBREVIATIONS: Readonly<Record<string, string>> = {
18
+ OpenHostService: 'OHS',
19
+ PublishedLanguage: 'PL',
20
+ AntiCorruptionLayer: 'ACL',
21
+ Conformist: 'CF',
22
+ Supplier: 'S',
23
+ Customer: 'C',
24
+ BigBallOfMud: 'BBoM',
25
+ SharedKernel: 'SK',
26
+ Partnership: 'P',
27
+ SeparateWays: 'SW',
28
+ };
29
+
30
+ /**
31
+ * Returns the abbreviated form of a side pattern AST node.
32
+ *
33
+ * Maps the `$type` (e.g. `OpenHostService`, `Conformist`) to its standard
34
+ * DDD abbreviation (e.g. `OHS`, `CF`). Unknown types are returned as-is.
35
+ */
36
+ function normalizePatternNode(pattern: SidePattern): string {
37
+ return PATTERN_ABBREVIATIONS[pattern.$type] ?? pattern.$type;
38
+ }
39
+
40
+ /**
41
+ * Returns `true` when the side pattern identifies a Big Ball of Mud participant.
42
+ *
43
+ * BBoM is surfaced as a cloud node shape on the bounded context itself, not as
44
+ * a text annotation in the edge badge, so it should be excluded from badge text.
45
+ */
46
+ function isBBoMSidePattern(pattern: SidePattern): boolean {
47
+ return isBigBallOfMud(pattern);
48
+ }
49
+
50
+ interface DiagramSelection {
51
+ selectedContextMapFqn?: string;
52
+ selectedContextMapName?: string;
53
+ }
54
+
55
+ interface RelationshipEdgeParams {
56
+ leftNode: SNode;
57
+ rightNode: SNode;
58
+ relationship: RelationshipView;
59
+ }
60
+
61
+ /**
62
+ * Generates context map diagrams in the **DDD community notation** style.
63
+ *
64
+ * Bounded contexts are rendered as ellipses. Relationships are rendered as edges
65
+ * with U/D (upstream/downstream) annotations and integration pattern labels at
66
+ * each end, matching the notation used in Eric Evans' "Domain-Driven Design" and
67
+ * Vaughn Vernon's "Implementing Domain-Driven Design".
68
+ *
69
+ * Edge label convention:
70
+ * - Position 0.1 (near source): `U [OHS, PL]` or `D [ACL]`
71
+ * - Position 0.9 (near target): `D [CF]` or `U [OHS]`
72
+ * - Position 0.5 (center): relationship type (e.g., "Customer/Supplier")
73
+ */
74
+ export class DomainLangContextMapDiagramGenerator extends LangiumDiagramGenerator {
75
+ protected override generateRoot(args: GeneratorContext): SModelRoot {
76
+ const document = args.document as LangiumDocument<Model>;
77
+ const query = fromDocument(document);
78
+ const selection = this.getSelection(args);
79
+ const contextMaps = query.contextMaps().toArray();
80
+
81
+ const selectedMap = this.selectContextMap(contextMaps, query, selection);
82
+ if (!selectedMap) {
83
+ return {
84
+ type: 'graph',
85
+ id: args.idCache.uniqueId('context-map:empty'),
86
+ children: [],
87
+ } satisfies SGraph;
88
+ }
89
+
90
+ // Fetch relationships first so the BBoM pre-pass can identify which BCs
91
+ // need the cloud node shape before any nodes are created.
92
+ const relationships = query.relationships()
93
+ .where((relationship) => relationship.source === 'ContextMap' && relationship.astNode.$container === selectedMap)
94
+ .toArray();
95
+
96
+ // BBoM pre-pass: collect the node keys of every bounded context that
97
+ // appears on a side annotated with the BigBallOfMud pattern. These get
98
+ // the `node:bbom` Sprotty type so the webview renders them as clouds.
99
+ const bboMNodeKeys = new Set<string>();
100
+ for (const rel of relationships) {
101
+ if (rel.type === 'directional') {
102
+ if (rel.left.patterns.some(isBBoMSidePattern)) {
103
+ bboMNodeKeys.add(this.getNodeKey(query, rel.left.context));
104
+ }
105
+ if (rel.right.patterns.some(isBBoMSidePattern)) {
106
+ bboMNodeKeys.add(this.getNodeKey(query, rel.right.context));
107
+ }
108
+ }
109
+ }
110
+
111
+ const nodeMap = new Map<string, SNode>();
112
+ this.collectContextMapNodes(selectedMap, query, nodeMap, bboMNodeKeys, args);
113
+
114
+ for (const relationship of relationships) {
115
+ this.ensureNode(nodeMap, query, relationship.left.context, bboMNodeKeys, args);
116
+ this.ensureNode(nodeMap, query, relationship.right.context, bboMNodeKeys, args);
117
+ }
118
+
119
+ const edges = relationships.flatMap((relationship) => {
120
+ const leftKey = this.getNodeKey(query, relationship.left.context);
121
+ const rightKey = this.getNodeKey(query, relationship.right.context);
122
+ const leftNode = nodeMap.get(leftKey);
123
+ const rightNode = nodeMap.get(rightKey);
124
+
125
+ if (!leftNode || !rightNode) {
126
+ return [];
127
+ }
128
+
129
+ return this.createRelationshipEdge({
130
+ leftNode,
131
+ rightNode,
132
+ relationship,
133
+ }, args);
134
+ });
135
+
136
+ return {
137
+ type: 'graph',
138
+ id: args.idCache.uniqueId(`context-map:${selectedMap.name}`, selectedMap),
139
+ children: [...nodeMap.values(), ...edges],
140
+ } satisfies SGraph;
141
+ }
142
+
143
+ // ── Relationship edges (DDD community notation) ──
144
+
145
+ /**
146
+ * Creates an edge with DDD community notation labels.
147
+ *
148
+ * For `->`: left = Upstream (U), right = Downstream (D)
149
+ * For `<-`: left = Downstream (D), right = Upstream (U)
150
+ * For `<->`: Partnership (bidirectional)
151
+ * For `><`: Separate Ways
152
+ *
153
+ * U/D labels are rendered as DDD notation badges with optional
154
+ * pattern boxes (e.g., `U [OHS, PL]`).
155
+ */
156
+ private createRelationshipEdge(
157
+ params: RelationshipEdgeParams,
158
+ args: GeneratorContext
159
+ ): SEdge[] {
160
+ const { leftNode, rightNode, relationship } = params;
161
+ const astNode = relationship.astNode;
162
+
163
+ if (relationship.type === 'symmetric') {
164
+ return this.createSymmetricEdge(leftNode, rightNode, relationship.kind, astNode, args);
165
+ }
166
+
167
+ // Directional
168
+ const { arrow, kind, left, right } = relationship;
169
+
170
+ // Determine source/target nodes based on arrow direction
171
+ const sourceId = arrow === '<-' ? rightNode.id : leftNode.id;
172
+ const targetId = arrow === '<-' ? leftNode.id : rightNode.id;
173
+
174
+ const edgeId = args.idCache.uniqueId(
175
+ `edge:${sourceId}:${targetId}`,
176
+ astNode
177
+ );
178
+
179
+ const children: SModelElement[] = [];
180
+
181
+ if (kind === 'Bidirectional') {
182
+ // No upstream/downstream roles — show patterns positionally
183
+ this.addUDBadge(children, edgeId, 'source', left.patterns, undefined, args);
184
+ this.addUDBadge(children, edgeId, 'target', right.patterns, undefined, args);
185
+ } else {
186
+ // Upstream/downstream or Customer/Supplier
187
+ const sourcePatterns = arrow === '<-' ? right.patterns : left.patterns;
188
+ const targetPatterns = arrow === '<-' ? left.patterns : right.patterns;
189
+ const sourceRole: 'U' | 'D' | 'S' | 'C' = kind === 'CustomerSupplier' ? 'S' : 'U';
190
+ const targetRole: 'U' | 'D' | 'S' | 'C' = kind === 'CustomerSupplier' ? 'C' : 'D';
191
+ this.addUDBadge(children, edgeId, 'source', sourcePatterns, sourceRole, args);
192
+ this.addUDBadge(children, edgeId, 'target', targetPatterns, targetRole, args);
193
+ }
194
+
195
+ // Center label: relationship kind
196
+ const centerLabel = this.formatRelationshipKind(kind);
197
+ if (centerLabel) {
198
+ children.push({
199
+ type: 'label:edge',
200
+ id: args.idCache.uniqueId(`${edgeId}:type`),
201
+ text: centerLabel,
202
+ edgePlacement: {
203
+ side: 'on',
204
+ position: 0.5,
205
+ rotate: false,
206
+ offset: 10,
207
+ },
208
+ } as unknown as SModelElement);
209
+ }
210
+
211
+ let edgeCssClasses: string[] | undefined;
212
+ if (arrow === '<->') {
213
+ edgeCssClasses = ['partnership'];
214
+ }
215
+
216
+ const edge: SEdge = {
217
+ type: 'edge',
218
+ id: edgeId,
219
+ sourceId,
220
+ targetId,
221
+ cssClasses: edgeCssClasses,
222
+ children: children.length > 0 ? children : undefined,
223
+ };
224
+
225
+ this.traceProvider.trace(edge as SModelElement, astNode as unknown as import('langium').AstNode);
226
+ return [edge];
227
+ }
228
+
229
+ /**
230
+ * Creates an undirected edge for symmetric relationships (SK, P, SW).
231
+ *
232
+ * Symmetric relationships have no upstream/downstream directionality.
233
+ * The center label shows the relationship kind (e.g. "Shared Kernel").
234
+ */
235
+ private createSymmetricEdge(
236
+ leftNode: SNode,
237
+ rightNode: SNode,
238
+ kind: string | undefined,
239
+ astNode: Relationship,
240
+ args: GeneratorContext
241
+ ): SEdge[] {
242
+ const edgeId = args.idCache.uniqueId(
243
+ `edge:${leftNode.id}:${rightNode.id}`,
244
+ astNode
245
+ );
246
+
247
+ const children: SModelElement[] = [];
248
+
249
+ const centerLabel = this.formatRelationshipKind(kind);
250
+ if (centerLabel) {
251
+ children.push({
252
+ type: 'label:edge',
253
+ id: args.idCache.uniqueId(`${edgeId}:type`),
254
+ text: centerLabel,
255
+ edgePlacement: {
256
+ side: 'on',
257
+ position: 0.5,
258
+ rotate: false,
259
+ offset: 10,
260
+ },
261
+ } as unknown as SModelElement);
262
+ }
263
+
264
+ let edgeCssClasses: string[] | undefined;
265
+ if (kind === 'SeparateWays') {
266
+ edgeCssClasses = ['separate-ways'];
267
+ } else if (kind === 'Partnership') {
268
+ edgeCssClasses = ['partnership'];
269
+ } else if (kind === 'SharedKernel') {
270
+ edgeCssClasses = ['shared-kernel'];
271
+ }
272
+
273
+ const edge: SEdge = {
274
+ type: 'edge',
275
+ id: edgeId,
276
+ sourceId: leftNode.id,
277
+ targetId: rightNode.id,
278
+ cssClasses: edgeCssClasses,
279
+ children: children.length > 0 ? children : undefined,
280
+ };
281
+
282
+ this.traceProvider.trace(edge as SModelElement, astNode as unknown as import('langium').AstNode);
283
+ return [edge];
284
+ }
285
+
286
+ /**
287
+ * Adds a U/D badge label at the source or target end of an edge.
288
+ *
289
+ * Patterns are normalised to their short abbreviations (e.g. `OpenHostService` →
290
+ * `OHS`) and `BBoM`/`BigBallOfMud` is excluded — BBoM is surfaced visually as a
291
+ * cloud node shape rather than a text annotation.
292
+ *
293
+ * Badge text format: `ROLE|PATTERNS` (e.g. `U|OHS, PL` or `D|ACL`).
294
+ * The webview `UDBadgeLabelView` renders this as a bordered box.
295
+ */
296
+ private addUDBadge(
297
+ children: SModelElement[],
298
+ edgeId: string,
299
+ placement: 'source' | 'target',
300
+ patterns: readonly SidePattern[],
301
+ role: 'U' | 'D' | 'S' | 'C' | undefined,
302
+ args: GeneratorContext
303
+ ): void {
304
+ // Normalise pattern names and strip BBoM (shown on node, not in badge).
305
+ // Also strip Supplier/Customer when they are already expressed as the role letter
306
+ // to prevent duplicate annotations like "S S" or "C C".
307
+ const badgePatterns = patterns
308
+ .filter((p) => !isBBoMSidePattern(p))
309
+ .filter((p) => !(role === 'S' && p.$type === 'Supplier'))
310
+ .filter((p) => !(role === 'C' && p.$type === 'Customer'))
311
+ .map(normalizePatternNode);
312
+
313
+ if (!role && badgePatterns.length === 0) {
314
+ return;
315
+ }
316
+
317
+ // Encode as ROLE|PATTERNS for UDBadgeLabelView parsing
318
+ const rolePart = role ?? '';
319
+ const patternPart = badgePatterns.length > 0 ? badgePatterns.join(', ') : '';
320
+ const badgeText = `${rolePart}|${patternPart}`;
321
+
322
+ children.push({
323
+ type: 'label:ud-badge',
324
+ id: args.idCache.uniqueId(`${edgeId}:${placement}`),
325
+ text: badgeText,
326
+ edgePlacement: {
327
+ side: 'on',
328
+ position: placement === 'source' ? 0.1 : 0.9,
329
+ rotate: false,
330
+ offset: 0,
331
+ },
332
+ } as unknown as SModelElement);
333
+ }
334
+
335
+ /**
336
+ * Formats the relationship type for the center edge label.
337
+ *
338
+ * Maps DomainLang keywords to DDD community notation display names:
339
+ * CustomerSupplier → Customer/Supplier
340
+ * SharedKernel → Shared Kernel
341
+ * UpstreamDownstream → Upstream/Downstream
342
+ * Partnership → Partnership
343
+ *
344
+ * For `<->` without explicit type, defaults to "Partnership".
345
+ * For `><`, defaults to "Separate Ways".
346
+ */
347
+ private formatRelationshipKind(kind: string | undefined): string | undefined {
348
+ if (!kind) return undefined;
349
+ return this.displayRelationshipKind(kind);
350
+ }
351
+
352
+ private displayRelationshipKind(kind: string): string | undefined {
353
+ switch (kind) {
354
+ // Directional kinds are already conveyed by U/D and C/S role badges — no center label needed
355
+ case 'CustomerSupplier': return undefined;
356
+ case 'UpstreamDownstream': return undefined;
357
+ // Symmetric and bidirectional kinds have no role badges, so label them explicitly
358
+ case 'SharedKernel': return 'Shared Kernel';
359
+ case 'SeparateWays': return 'Separate Ways';
360
+ case 'Partnership': return 'Partnership';
361
+ default: return kind;
362
+ }
363
+ }
364
+
365
+ // ── Node generation ──
366
+
367
+ private collectContextMapNodes(
368
+ selectedMap: ContextMap,
369
+ query: Query,
370
+ nodeMap: Map<string, SNode>,
371
+ bboMNodeKeys: ReadonlySet<string>,
372
+ args: GeneratorContext
373
+ ): void {
374
+ for (const boundedContextRef of selectedMap.boundedContexts) {
375
+ for (const item of boundedContextRef.items) {
376
+ this.ensureNodeForContextMapItem(item, query, nodeMap, bboMNodeKeys, args);
377
+ }
378
+
379
+ if (boundedContextRef.items.length === 0 && boundedContextRef.$refText) {
380
+ this.ensureUnresolvedNode(nodeMap, boundedContextRef.$refText, args);
381
+ }
382
+ }
383
+ }
384
+
385
+ private ensureNodeForContextMapItem(
386
+ item: { ref?: BoundedContext; $refText?: string },
387
+ query: Query,
388
+ nodeMap: Map<string, SNode>,
389
+ bboMNodeKeys: ReadonlySet<string>,
390
+ args: GeneratorContext
391
+ ): void {
392
+ const boundedContext = item.ref;
393
+ if (!boundedContext) {
394
+ if (item.$refText) {
395
+ this.ensureUnresolvedNode(nodeMap, item.$refText, args);
396
+ }
397
+ return;
398
+ }
399
+
400
+ const nodeKey = this.getNodeKey(query, boundedContext);
401
+ if (nodeMap.has(nodeKey)) {
402
+ return;
403
+ }
404
+
405
+ const nodeId = args.idCache.uniqueId(`node:${nodeKey}`, boundedContext);
406
+ const node = this.createNode(nodeId, boundedContext.name, bboMNodeKeys.has(nodeKey));
407
+ this.traceProvider.trace(node as SModelElement, boundedContext);
408
+ nodeMap.set(nodeKey, node);
409
+ }
410
+
411
+ private createNode(id: string, label: string, isBBoM = false): SNode {
412
+ return {
413
+ type: isBBoM ? 'node:bbom' : 'node',
414
+ id,
415
+ position: { x: 0, y: 0 },
416
+ size: {
417
+ width: NODE_WIDTH,
418
+ height: NODE_HEIGHT,
419
+ },
420
+ layout: 'vbox',
421
+ layoutOptions: {
422
+ hAlign: 'center',
423
+ vAlign: 'center',
424
+ resizeContainer: false,
425
+ paddingTop: 10,
426
+ paddingBottom: 10,
427
+ paddingLeft: 20,
428
+ paddingRight: 20,
429
+ },
430
+ children: [this.createNodeLabel(id, label)],
431
+ };
432
+ }
433
+
434
+ private createNodeLabel(nodeId: string, label: string): SModelElement {
435
+ return {
436
+ type: 'label',
437
+ id: `${nodeId}:label`,
438
+ text: label,
439
+ } as unknown as SModelElement;
440
+ }
441
+
442
+ private ensureNode(
443
+ nodeMap: Map<string, SNode>,
444
+ query: Query,
445
+ boundedContext: BoundedContext,
446
+ bboMNodeKeys: ReadonlySet<string>,
447
+ args: GeneratorContext
448
+ ): void {
449
+ const nodeKey = this.getNodeKey(query, boundedContext);
450
+ if (nodeMap.has(nodeKey)) {
451
+ return;
452
+ }
453
+
454
+ const nodeId = args.idCache.uniqueId(`node:${nodeKey}`, boundedContext);
455
+ const node = this.createNode(nodeId, boundedContext.name, bboMNodeKeys.has(nodeKey));
456
+ this.traceProvider.trace(node as SModelElement, boundedContext);
457
+ nodeMap.set(nodeKey, node);
458
+ }
459
+
460
+ private ensureUnresolvedNode(nodeMap: Map<string, SNode>, label: string, args: GeneratorContext): void {
461
+ const key = `unresolved:${label}`;
462
+ if (nodeMap.has(key)) {
463
+ return;
464
+ }
465
+
466
+ const nodeId = args.idCache.uniqueId(`node:${key}`);
467
+ nodeMap.set(key, this.createNode(nodeId, label));
468
+ }
469
+
470
+ private getNodeKey(query: Query, boundedContext: BoundedContext): string {
471
+ const fqn = query.fqn(boundedContext);
472
+ return fqn ?? boundedContext.name;
473
+ }
474
+
475
+ // ── Selection helpers ──
476
+
477
+ private getSelection(args: GeneratorContext): DiagramSelection {
478
+ const options = args.options;
479
+ if (typeof options !== 'object' || options === null) {
480
+ return {};
481
+ }
482
+
483
+ const selectedContextMapFqn = this.getStringOption(options, 'selectedContextMapFqn');
484
+ const selectedContextMapName = this.getStringOption(options, 'selectedContextMapName');
485
+ return {
486
+ selectedContextMapFqn,
487
+ selectedContextMapName,
488
+ };
489
+ }
490
+
491
+ private getStringOption(options: object, key: string): string | undefined {
492
+ const value = Reflect.get(options, key);
493
+ return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
494
+ }
495
+
496
+ private selectContextMap(contextMaps: readonly ContextMap[], query: Query, selection: DiagramSelection): ContextMap | undefined {
497
+ if (selection.selectedContextMapFqn) {
498
+ const byFqn = contextMaps.find((contextMap) => query.fqn(contextMap) === selection.selectedContextMapFqn);
499
+ if (byFqn) {
500
+ return byFqn;
501
+ }
502
+ }
503
+
504
+ if (selection.selectedContextMapName) {
505
+ const byName = contextMaps.find((contextMap) => contextMap.name === selection.selectedContextMapName);
506
+ if (byName) {
507
+ return byName;
508
+ }
509
+ }
510
+
511
+ return contextMaps[0];
512
+ }
513
+ }
@@ -0,0 +1,43 @@
1
+ import type { LayoutOptions } from 'elkjs/lib/elk-api.js';
2
+ import { DefaultLayoutConfigurator } from 'sprotty-elk/lib/elk-layout.js';
3
+ import type { SGraph, SNode, SModelIndex, SEdge } from 'sprotty-protocol';
4
+
5
+ /**
6
+ * ELK layout configurator for DomainLang context map diagrams.
7
+ *
8
+ * Uses the `layered` algorithm with **DOWN** direction (top-to-bottom) so
9
+ * upstream contexts appear above downstream contexts, matching the conventional
10
+ * DDD Context Map layout direction.
11
+ */
12
+ export class ContextMapLayoutConfigurator extends DefaultLayoutConfigurator {
13
+ protected override graphOptions(_graph: SGraph, _index: SModelIndex): LayoutOptions {
14
+ return {
15
+ 'elk.algorithm': 'layered',
16
+ 'elk.direction': 'DOWN',
17
+ 'elk.layered.nodePlacement.strategy': 'BRANDES_KOEPF',
18
+ 'elk.spacing.nodeNode': '100',
19
+ 'elk.layered.spacing.nodeNodeBetweenLayers': '140',
20
+ 'elk.spacing.edgeNode': '60',
21
+ 'elk.spacing.edgeEdge': '40',
22
+ // Edge routing mode is irrelevant — the webview SmoothBezierEdgeView
23
+ // ignores ELK routing points and computes dynamic bezier curves
24
+ // anchored directly to node ellipses with obstacle avoidance.
25
+ 'elk.edgeRouting': 'POLYLINE',
26
+ 'elk.layered.mergeEdges': 'false',
27
+ 'elk.layered.crossingMinimization.strategy': 'LAYER_SWEEP',
28
+ 'elk.layered.thoroughness': '7',
29
+ };
30
+ }
31
+
32
+ protected override nodeOptions(_node: SNode, _index: SModelIndex): LayoutOptions {
33
+ return {
34
+ 'elk.layered.nodePlacement.bk.fixedAlignment': 'BALANCED',
35
+ };
36
+ }
37
+
38
+ protected override edgeOptions(_edge: SEdge, _index: SModelIndex): LayoutOptions {
39
+ return {
40
+ 'elk.layered.priority.direction': '1',
41
+ };
42
+ }
43
+ }