@domainlang/language 0.1.81

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 (188) hide show
  1. package/README.md +32 -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 +55 -0
  6. package/out/domain-lang-module.js +59 -0
  7. package/out/domain-lang-module.js.map +1 -0
  8. package/out/generated/ast.d.ts +770 -0
  9. package/out/generated/ast.js +565 -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 +2502 -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 +13 -0
  18. package/out/index.js +17 -0
  19. package/out/index.js.map +1 -0
  20. package/out/lsp/domain-lang-completion.d.ts +37 -0
  21. package/out/lsp/domain-lang-completion.js +452 -0
  22. package/out/lsp/domain-lang-completion.js.map +1 -0
  23. package/out/lsp/domain-lang-formatter.d.ts +15 -0
  24. package/out/lsp/domain-lang-formatter.js +43 -0
  25. package/out/lsp/domain-lang-formatter.js.map +1 -0
  26. package/out/lsp/domain-lang-naming.d.ts +34 -0
  27. package/out/lsp/domain-lang-naming.js +49 -0
  28. package/out/lsp/domain-lang-naming.js.map +1 -0
  29. package/out/lsp/domain-lang-scope.d.ts +59 -0
  30. package/out/lsp/domain-lang-scope.js +102 -0
  31. package/out/lsp/domain-lang-scope.js.map +1 -0
  32. package/out/lsp/hover/ddd-pattern-explanations.d.ts +50 -0
  33. package/out/lsp/hover/ddd-pattern-explanations.js +196 -0
  34. package/out/lsp/hover/ddd-pattern-explanations.js.map +1 -0
  35. package/out/lsp/hover/domain-lang-hover.d.ts +19 -0
  36. package/out/lsp/hover/domain-lang-hover.js +306 -0
  37. package/out/lsp/hover/domain-lang-hover.js.map +1 -0
  38. package/out/lsp/hover/domain-lang-keywords.d.ts +13 -0
  39. package/out/lsp/hover/domain-lang-keywords.js +47 -0
  40. package/out/lsp/hover/domain-lang-keywords.js.map +1 -0
  41. package/out/main-browser.d.ts +1 -0
  42. package/out/main-browser.js +11 -0
  43. package/out/main-browser.js.map +1 -0
  44. package/out/main.d.ts +1 -0
  45. package/out/main.js +74 -0
  46. package/out/main.js.map +1 -0
  47. package/out/sdk/ast-augmentation.d.ts +136 -0
  48. package/out/sdk/ast-augmentation.js +62 -0
  49. package/out/sdk/ast-augmentation.js.map +1 -0
  50. package/out/sdk/index.d.ts +94 -0
  51. package/out/sdk/index.js +97 -0
  52. package/out/sdk/index.js.map +1 -0
  53. package/out/sdk/indexes.d.ts +16 -0
  54. package/out/sdk/indexes.js +97 -0
  55. package/out/sdk/indexes.js.map +1 -0
  56. package/out/sdk/loader-node.d.ts +47 -0
  57. package/out/sdk/loader-node.js +104 -0
  58. package/out/sdk/loader-node.js.map +1 -0
  59. package/out/sdk/loader.d.ts +49 -0
  60. package/out/sdk/loader.js +85 -0
  61. package/out/sdk/loader.js.map +1 -0
  62. package/out/sdk/patterns.d.ts +93 -0
  63. package/out/sdk/patterns.js +123 -0
  64. package/out/sdk/patterns.js.map +1 -0
  65. package/out/sdk/query.d.ts +90 -0
  66. package/out/sdk/query.js +679 -0
  67. package/out/sdk/query.js.map +1 -0
  68. package/out/sdk/resolution.d.ts +52 -0
  69. package/out/sdk/resolution.js +68 -0
  70. package/out/sdk/resolution.js.map +1 -0
  71. package/out/sdk/types.d.ts +301 -0
  72. package/out/sdk/types.js +8 -0
  73. package/out/sdk/types.js.map +1 -0
  74. package/out/services/dependency-analyzer.d.ts +94 -0
  75. package/out/services/dependency-analyzer.js +279 -0
  76. package/out/services/dependency-analyzer.js.map +1 -0
  77. package/out/services/dependency-resolver.d.ts +123 -0
  78. package/out/services/dependency-resolver.js +252 -0
  79. package/out/services/dependency-resolver.js.map +1 -0
  80. package/out/services/git-url-resolver.browser.d.ts +18 -0
  81. package/out/services/git-url-resolver.browser.js +15 -0
  82. package/out/services/git-url-resolver.browser.js.map +1 -0
  83. package/out/services/git-url-resolver.d.ts +192 -0
  84. package/out/services/git-url-resolver.js +382 -0
  85. package/out/services/git-url-resolver.js.map +1 -0
  86. package/out/services/governance-validator.d.ts +80 -0
  87. package/out/services/governance-validator.js +159 -0
  88. package/out/services/governance-validator.js.map +1 -0
  89. package/out/services/import-resolver.d.ts +18 -0
  90. package/out/services/import-resolver.js +22 -0
  91. package/out/services/import-resolver.js.map +1 -0
  92. package/out/services/performance-optimizer.d.ts +60 -0
  93. package/out/services/performance-optimizer.js +140 -0
  94. package/out/services/performance-optimizer.js.map +1 -0
  95. package/out/services/relationship-inference.d.ts +11 -0
  96. package/out/services/relationship-inference.js +98 -0
  97. package/out/services/relationship-inference.js.map +1 -0
  98. package/out/services/workspace-manager.d.ts +76 -0
  99. package/out/services/workspace-manager.js +323 -0
  100. package/out/services/workspace-manager.js.map +1 -0
  101. package/out/syntaxes/domain-lang.monarch.d.ts +76 -0
  102. package/out/syntaxes/domain-lang.monarch.js +29 -0
  103. package/out/syntaxes/domain-lang.monarch.js.map +1 -0
  104. package/out/utils/import-utils.d.ts +57 -0
  105. package/out/utils/import-utils.js +228 -0
  106. package/out/utils/import-utils.js.map +1 -0
  107. package/out/validation/bounded-context.d.ts +11 -0
  108. package/out/validation/bounded-context.js +79 -0
  109. package/out/validation/bounded-context.js.map +1 -0
  110. package/out/validation/classification.d.ts +3 -0
  111. package/out/validation/classification.js +3 -0
  112. package/out/validation/classification.js.map +1 -0
  113. package/out/validation/constants.d.ts +77 -0
  114. package/out/validation/constants.js +96 -0
  115. package/out/validation/constants.js.map +1 -0
  116. package/out/validation/domain-lang-validator.d.ts +2 -0
  117. package/out/validation/domain-lang-validator.js +27 -0
  118. package/out/validation/domain-lang-validator.js.map +1 -0
  119. package/out/validation/domain.d.ts +11 -0
  120. package/out/validation/domain.js +18 -0
  121. package/out/validation/domain.js.map +1 -0
  122. package/out/validation/import.d.ts +44 -0
  123. package/out/validation/import.js +135 -0
  124. package/out/validation/import.js.map +1 -0
  125. package/out/validation/maps.d.ts +21 -0
  126. package/out/validation/maps.js +56 -0
  127. package/out/validation/maps.js.map +1 -0
  128. package/out/validation/metadata.d.ts +7 -0
  129. package/out/validation/metadata.js +12 -0
  130. package/out/validation/metadata.js.map +1 -0
  131. package/out/validation/model.d.ts +12 -0
  132. package/out/validation/model.js +29 -0
  133. package/out/validation/model.js.map +1 -0
  134. package/out/validation/relationships.d.ts +12 -0
  135. package/out/validation/relationships.js +94 -0
  136. package/out/validation/relationships.js.map +1 -0
  137. package/out/validation/shared.d.ts +6 -0
  138. package/out/validation/shared.js +12 -0
  139. package/out/validation/shared.js.map +1 -0
  140. package/package.json +97 -0
  141. package/src/ast-augmentation.ts +5 -0
  142. package/src/domain-lang-module.ts +100 -0
  143. package/src/domain-lang.langium +356 -0
  144. package/src/generated/ast.ts +999 -0
  145. package/src/generated/grammar.ts +2504 -0
  146. package/src/generated/module.ts +25 -0
  147. package/src/index.ts +17 -0
  148. package/src/lsp/domain-lang-completion.ts +514 -0
  149. package/src/lsp/domain-lang-formatter.ts +51 -0
  150. package/src/lsp/domain-lang-naming.ts +56 -0
  151. package/src/lsp/domain-lang-scope.ts +137 -0
  152. package/src/lsp/hover/ddd-pattern-explanations.ts +237 -0
  153. package/src/lsp/hover/domain-lang-hover.ts +340 -0
  154. package/src/lsp/hover/domain-lang-keywords.ts +50 -0
  155. package/src/main-browser.ts +15 -0
  156. package/src/main.ts +85 -0
  157. package/src/sdk/README.md +297 -0
  158. package/src/sdk/ast-augmentation.ts +157 -0
  159. package/src/sdk/index.ts +128 -0
  160. package/src/sdk/indexes.ts +155 -0
  161. package/src/sdk/loader-node.ts +126 -0
  162. package/src/sdk/loader.ts +99 -0
  163. package/src/sdk/patterns.ts +147 -0
  164. package/src/sdk/query.ts +802 -0
  165. package/src/sdk/resolution.ts +78 -0
  166. package/src/sdk/types.ts +346 -0
  167. package/src/services/dependency-analyzer.ts +381 -0
  168. package/src/services/dependency-resolver.ts +334 -0
  169. package/src/services/git-url-resolver.browser.ts +31 -0
  170. package/src/services/git-url-resolver.ts +524 -0
  171. package/src/services/governance-validator.ts +219 -0
  172. package/src/services/import-resolver.ts +30 -0
  173. package/src/services/performance-optimizer.ts +170 -0
  174. package/src/services/relationship-inference.ts +121 -0
  175. package/src/services/workspace-manager.ts +416 -0
  176. package/src/syntaxes/domain-lang.monarch.ts +29 -0
  177. package/src/utils/import-utils.ts +274 -0
  178. package/src/validation/bounded-context.ts +99 -0
  179. package/src/validation/classification.ts +5 -0
  180. package/src/validation/constants.ts +124 -0
  181. package/src/validation/domain-lang-validator.ts +33 -0
  182. package/src/validation/domain.ts +24 -0
  183. package/src/validation/import.ts +171 -0
  184. package/src/validation/maps.ts +72 -0
  185. package/src/validation/metadata.ts +14 -0
  186. package/src/validation/model.ts +37 -0
  187. package/src/validation/relationships.ts +154 -0
  188. package/src/validation/shared.ts +14 -0
@@ -0,0 +1,25 @@
1
+ /******************************************************************************
2
+ * This file was generated by langium-cli 4.1.0.
3
+ * DO NOT EDIT MANUALLY!
4
+ ******************************************************************************/
5
+
6
+ import type { LangiumSharedCoreServices, LangiumCoreServices, LangiumGeneratedCoreServices, LangiumGeneratedSharedCoreServices, LanguageMetaData, Module } from 'langium';
7
+ import { DomainLangAstReflection } from './ast.js';
8
+ import { DomainLangGrammar } from './grammar.js';
9
+
10
+ export const DomainLangLanguageMetaData = {
11
+ languageId: 'domain-lang',
12
+ fileExtensions: ['.dlang'],
13
+ caseInsensitive: false,
14
+ mode: 'development'
15
+ } as const satisfies LanguageMetaData;
16
+
17
+ export const DomainLangGeneratedSharedModule: Module<LangiumSharedCoreServices, LangiumGeneratedSharedCoreServices> = {
18
+ AstReflection: () => new DomainLangAstReflection()
19
+ };
20
+
21
+ export const DomainLangGeneratedModule: Module<LangiumCoreServices, LangiumGeneratedCoreServices> = {
22
+ Grammar: () => DomainLangGrammar(),
23
+ LanguageMetaData: () => DomainLangLanguageMetaData,
24
+ parser: {}
25
+ };
package/src/index.ts ADDED
@@ -0,0 +1,17 @@
1
+ export * from './domain-lang-module.js';
2
+ export * from './generated/ast.js';
3
+ export * from './generated/grammar.js';
4
+ export * from './generated/module.js';
5
+ // Note: main.js is intentionally NOT exported here - it's the LSP entry point
6
+ // and creates a connection when imported, which breaks CLI/SDK standalone usage
7
+ export * from './ast-augmentation.js';
8
+
9
+ // Export services
10
+ export * from './services/workspace-manager.js';
11
+ export * from './services/dependency-resolver.js';
12
+ export * from './services/dependency-analyzer.js';
13
+ export * from './services/governance-validator.js';
14
+ export * from './services/import-resolver.js';
15
+ export * from './services/relationship-inference.js';
16
+ export * from './services/git-url-resolver.js';
17
+ export * from './services/performance-optimizer.js';
@@ -0,0 +1,514 @@
1
+ /**
2
+ * Completion provider for DomainLang - context-aware, grammar-aligned.
3
+ *
4
+ * **Design:**
5
+ * - Context-aware: Only suggests what's valid at cursor position
6
+ * - Grammar-aligned: Completions match grammar structure exactly
7
+ * - Simple: Uses parent node to determine context
8
+ * - Maintainable: Clear mapping from grammar to completions
9
+ */
10
+
11
+ import { CompletionAcceptor, CompletionContext, DefaultCompletionProvider, NextFeature } from 'langium/lsp';
12
+ import { CompletionItemKind, InsertTextFormat } from 'vscode-languageserver';
13
+ import * as ast from '../generated/ast.js';
14
+
15
+ /**
16
+ * Top-level snippet templates for creating new AST nodes.
17
+ */
18
+ const TOP_LEVEL_SNIPPETS = [
19
+ {
20
+ label: '⚡ Domain (simple)',
21
+ kind: CompletionItemKind.Snippet,
22
+ insertText: 'Domain ${1:Name} {}',
23
+ documentation: '📝 Snippet: Create a simple domain',
24
+ sortText: '0_snippet_domain_simple'
25
+ },
26
+ {
27
+ label: '⚡ Domain (detailed)',
28
+ kind: CompletionItemKind.Snippet,
29
+ insertText: [
30
+ 'Domain ${1:Name} {',
31
+ '\tdescription: "${2:Description}"',
32
+ '\tvision: "${3:Vision}"',
33
+ '\tclassification: ${4:CoreDomain}',
34
+ '}'
35
+ ].join('\n'),
36
+ documentation: '📝 Snippet: Create a domain with description and vision',
37
+ sortText: '0_snippet_domain_detailed'
38
+ },
39
+ {
40
+ label: '⚡ BoundedContext (simple)',
41
+ kind: CompletionItemKind.Snippet,
42
+ insertText: 'bc ${1:Name} for ${2:Domain} as ${3:Core} by ${4:Team}',
43
+ documentation: '📝 Snippet: Quick bounded context definition',
44
+ sortText: '0_snippet_bc_simple'
45
+ },
46
+ {
47
+ label: '⚡ BoundedContext (detailed)',
48
+ kind: CompletionItemKind.Snippet,
49
+ insertText: [
50
+ 'BoundedContext ${1:Name} for ${2:Domain} {',
51
+ '\tdescription: "${3:Description}"',
52
+ '\tteam: ${4:Team}',
53
+ '\trole: ${5:Core}',
54
+ '\t',
55
+ '\tterminology {',
56
+ '\t\tterm ${6:Term}: "${7:Definition}"',
57
+ '\t}',
58
+ '}'
59
+ ].join('\n'),
60
+ documentation: '📝 Snippet: Full bounded context with all common blocks',
61
+ sortText: '0_snippet_bc_detailed'
62
+ },
63
+ {
64
+ label: '⚡ ContextMap',
65
+ kind: CompletionItemKind.Snippet,
66
+ insertText: [
67
+ 'ContextMap ${1:Name} {',
68
+ '\tcontains ${2:Context1}, ${3:Context2}',
69
+ '}'
70
+ ].join('\n'),
71
+ documentation: '📝 Snippet: Create a context map',
72
+ sortText: '0_snippet_contextmap'
73
+ },
74
+ {
75
+ label: '⚡ DomainMap',
76
+ kind: CompletionItemKind.Snippet,
77
+ insertText: [
78
+ 'DomainMap ${1:Name} {',
79
+ '\tcontains ${2:Domain1}, ${3:Domain2}',
80
+ '}'
81
+ ].join('\n'),
82
+ documentation: '📝 Snippet: Create a domain map',
83
+ sortText: '0_snippet_domainmap'
84
+ },
85
+ {
86
+ label: '⚡ Team',
87
+ kind: CompletionItemKind.Snippet,
88
+ insertText: 'Team ${1:TeamName}',
89
+ documentation: '📝 Snippet: Define a team',
90
+ sortText: '0_snippet_team'
91
+ },
92
+ {
93
+ label: '⚡ Classification',
94
+ kind: CompletionItemKind.Snippet,
95
+ insertText: 'Classification ${1:Name}',
96
+ documentation: '📝 Snippet: Define a reusable classification label',
97
+ sortText: '0_snippet_classification'
98
+ },
99
+ {
100
+ label: '⚡ Metadata',
101
+ kind: CompletionItemKind.Snippet,
102
+ insertText: 'Metadata ${1:KeyName}',
103
+ documentation: '📝 Snippet: Define a metadata key',
104
+ sortText: '0_snippet_metadata'
105
+ },
106
+ {
107
+ label: '⚡ Namespace',
108
+ kind: CompletionItemKind.Snippet,
109
+ insertText: [
110
+ 'Namespace ${1:name.space} {',
111
+ '\t$0',
112
+ '}'
113
+ ].join('\n'),
114
+ documentation: '📝 Snippet: Create a hierarchical namespace',
115
+ sortText: '0_snippet_namespace'
116
+ }
117
+ ] as const;
118
+
119
+ export class DomainLangCompletionProvider extends DefaultCompletionProvider {
120
+ protected override completionFor(
121
+ context: CompletionContext,
122
+ next: NextFeature,
123
+ acceptor: CompletionAcceptor
124
+ ): void {
125
+ const node = context.node;
126
+ if (!node) {
127
+ super.completionFor(context, next, acceptor);
128
+ return;
129
+ }
130
+
131
+ // Strategy: Check node type and container to determine what's allowed at cursor position
132
+
133
+ // Check if cursor is after the node (for top-level positioning)
134
+ const offset = context.offset;
135
+ const nodeEnd = node.$cstNode?.end ?? 0;
136
+ const isAfterNode = offset >= nodeEnd;
137
+
138
+ // If we're positioned after a BC/Domain (e.g., on next line): show top-level
139
+ if ((ast.isBoundedContext(node) || ast.isDomain(node)) && isAfterNode) {
140
+ this.addTopLevelSnippets(acceptor, context);
141
+ // Let Langium provide keywords like "bc", "Domain", etc.
142
+ super.completionFor(context, next, acceptor);
143
+ return;
144
+ }
145
+
146
+ // If we're AT a BoundedContext node: only BC documentation blocks
147
+ if (ast.isBoundedContext(node)) {
148
+ this.addBoundedContextCompletions(node, acceptor, context);
149
+ super.completionFor(context, next, acceptor);
150
+ return;
151
+ }
152
+
153
+ // If we're AT a Domain node: only Domain documentation blocks
154
+ if (ast.isDomain(node)) {
155
+ this.addDomainCompletions(node, acceptor, context);
156
+ super.completionFor(context, next, acceptor);
157
+ return;
158
+ }
159
+
160
+ // If we're AT a ContextMap node: relationships and contains
161
+ if (ast.isContextMap(node)) {
162
+ this.addContextMapCompletions(node, acceptor, context);
163
+ super.completionFor(context, next, acceptor);
164
+ return;
165
+ }
166
+
167
+ // If we're AT a DomainMap node: contains
168
+ if (ast.isDomainMap(node)) {
169
+ this.addDomainMapCompletions(node, acceptor, context);
170
+ super.completionFor(context, next, acceptor);
171
+ return;
172
+ }
173
+
174
+ // If we're AT the Model or NamespaceDeclaration level: all top-level constructs
175
+ if (ast.isModel(node) || ast.isNamespaceDeclaration(node)) {
176
+ this.addTopLevelSnippets(acceptor, context);
177
+ super.completionFor(context, next, acceptor);
178
+ return;
179
+ }
180
+
181
+ const container = node.$container;
182
+
183
+ // Inside BoundedContext body: suggest missing scalar properties and collections
184
+ if (ast.isBoundedContext(container)) {
185
+ this.addBoundedContextCompletions(container, acceptor, context);
186
+ super.completionFor(context, next, acceptor);
187
+ return;
188
+ }
189
+
190
+ // Inside Domain body: suggest missing scalar properties
191
+ if (ast.isDomain(container)) {
192
+ this.addDomainCompletions(container, acceptor, context);
193
+ super.completionFor(context, next, acceptor);
194
+ return;
195
+ }
196
+
197
+ // Inside ContextMap body: relationships and contains
198
+ if (ast.isContextMap(container)) {
199
+ this.addContextMapCompletions(container, acceptor, context);
200
+ super.completionFor(context, next, acceptor);
201
+ return;
202
+ }
203
+
204
+ // Inside DomainMap body: contains
205
+ if (ast.isDomainMap(container)) {
206
+ this.addDomainMapCompletions(container, acceptor, context);
207
+ super.completionFor(context, next, acceptor);
208
+ return;
209
+ }
210
+
211
+ if (ast.isRelationship(node) || ast.isRelationship(container)) {
212
+ this.addRelationshipCompletions(acceptor, context);
213
+ super.completionFor(context, next, acceptor);
214
+ return;
215
+ }
216
+
217
+ // Top level container (Model or NamespaceDeclaration): all top-level constructs
218
+ if (ast.isModel(container) || ast.isNamespaceDeclaration(container)) {
219
+ this.addTopLevelSnippets(acceptor, context);
220
+ }
221
+
222
+ // Let Langium handle default completions
223
+ super.completionFor(context, next, acceptor);
224
+ }
225
+
226
+ private addTopLevelSnippets(acceptor: CompletionAcceptor, context: CompletionContext): void {
227
+ for (const snippet of TOP_LEVEL_SNIPPETS) {
228
+ acceptor(context, {
229
+ label: snippet.label,
230
+ kind: snippet.kind,
231
+ insertText: snippet.insertText,
232
+ insertTextFormat: InsertTextFormat.Snippet,
233
+ documentation: snippet.documentation,
234
+ sortText: snippet.sortText
235
+ });
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Add property/collection completions for BoundedContext.
241
+ */
242
+ private addBoundedContextCompletions(
243
+ node: ast.BoundedContext,
244
+ acceptor: CompletionAcceptor,
245
+ context: CompletionContext
246
+ ): void {
247
+ if (!node.description) {
248
+ acceptor(context, {
249
+ label: '⚡ description',
250
+ kind: CompletionItemKind.Snippet,
251
+ insertText: 'description: "${1:Description}"',
252
+ insertTextFormat: InsertTextFormat.Snippet,
253
+ documentation: '📝 Snippet: Describe the bounded context\'s responsibility',
254
+ sortText: '0_snippet_description'
255
+ });
256
+ }
257
+
258
+ if (node.team.length === 0) {
259
+ acceptor(context, {
260
+ label: '⚡ team',
261
+ kind: CompletionItemKind.Snippet,
262
+ insertText: 'team: ${1:TeamName}',
263
+ insertTextFormat: InsertTextFormat.Snippet,
264
+ documentation: '📝 Snippet: Assign the responsible team',
265
+ sortText: '0_snippet_team'
266
+ });
267
+ }
268
+
269
+ if (node.classification.length === 0) {
270
+ acceptor(context, {
271
+ label: '⚡ classification',
272
+ kind: CompletionItemKind.Snippet,
273
+ insertText: 'classification: ${1:Core}',
274
+ insertTextFormat: InsertTextFormat.Snippet,
275
+ documentation: '📝 Snippet: Assign the strategic classification (Core, Supporting, Generic)',
276
+ sortText: '0_snippet_classification'
277
+ });
278
+ }
279
+
280
+ if (!node.businessModel) {
281
+ acceptor(context, {
282
+ label: '⚡ businessModel',
283
+ kind: CompletionItemKind.Snippet,
284
+ insertText: 'businessModel: ${1:Commercial}',
285
+ insertTextFormat: InsertTextFormat.Snippet,
286
+ documentation: '📝 Snippet: Classify the business model',
287
+ sortText: '0_snippet_businessModel'
288
+ });
289
+ }
290
+
291
+ if (!node.evolution) {
292
+ acceptor(context, {
293
+ label: '⚡ evolution',
294
+ kind: CompletionItemKind.Snippet,
295
+ insertText: 'evolution: ${1:Product}',
296
+ insertTextFormat: InsertTextFormat.Snippet,
297
+ documentation: '📝 Snippet: Define the evolution stage (Genesis, Custom, Product, Commodity)',
298
+ sortText: '0_snippet_evolution'
299
+ });
300
+ }
301
+
302
+ if (node.terminology.length === 0) {
303
+ acceptor(context, {
304
+ label: '⚡ terminology',
305
+ kind: CompletionItemKind.Snippet,
306
+ insertText: [
307
+ 'terminology {',
308
+ '\tterm ${1:Term}: "${2:Definition}"',
309
+ '}'
310
+ ].join('\n'),
311
+ insertTextFormat: InsertTextFormat.Snippet,
312
+ documentation: '📝 Snippet: Define ubiquitous language terms',
313
+ sortText: '0_snippet_terminology'
314
+ });
315
+ }
316
+
317
+ if (node.decisions.length === 0) {
318
+ acceptor(context, {
319
+ label: '⚡ decisions',
320
+ kind: CompletionItemKind.Snippet,
321
+ insertText: [
322
+ 'decisions {',
323
+ '\tdecision [${1|technical,business|}] ${2:DecisionName}: "${3:Rationale}"',
324
+ '}'
325
+ ].join('\n'),
326
+ insertTextFormat: InsertTextFormat.Snippet,
327
+ documentation: '📝 Snippet: Document architectural decisions',
328
+ sortText: '0_snippet_decisions'
329
+ });
330
+ }
331
+
332
+ if (node.relationships.length === 0) {
333
+ acceptor(context, {
334
+ label: '⚡ relationships',
335
+ kind: CompletionItemKind.Snippet,
336
+ insertText: [
337
+ 'relationships {',
338
+ '\t${1:Context1} -> ${2:Context2}',
339
+ '}'
340
+ ].join('\n'),
341
+ insertTextFormat: InsertTextFormat.Snippet,
342
+ documentation: '📝 Snippet: Define relationships with other bounded contexts',
343
+ sortText: '0_snippet_relationships'
344
+ });
345
+ }
346
+
347
+ if (node.metadata.length === 0) {
348
+ acceptor(context, {
349
+ label: '⚡ metadata',
350
+ kind: CompletionItemKind.Snippet,
351
+ insertText: [
352
+ 'metadata {',
353
+ '\t${1:Language}: "${2:TypeScript}"',
354
+ '}'
355
+ ].join('\n'),
356
+ insertTextFormat: InsertTextFormat.Snippet,
357
+ documentation: '📝 Snippet: Add metadata key-value pairs',
358
+ sortText: '0_snippet_metadata'
359
+ });
360
+ }
361
+ }
362
+
363
+ /**
364
+ * Add property completions for Domain.
365
+ */
366
+ private addDomainCompletions(
367
+ node: ast.Domain,
368
+ acceptor: CompletionAcceptor,
369
+ context: CompletionContext
370
+ ): void {
371
+ if (!node.description) {
372
+ acceptor(context, {
373
+ label: '⚡ description',
374
+ kind: CompletionItemKind.Snippet,
375
+ insertText: 'description: "${1:Description}"',
376
+ insertTextFormat: InsertTextFormat.Snippet,
377
+ documentation: '📝 Snippet: Describe what this domain encompasses',
378
+ sortText: '0_snippet_description'
379
+ });
380
+ }
381
+
382
+ if (!node.vision) {
383
+ acceptor(context, {
384
+ label: '⚡ vision',
385
+ kind: CompletionItemKind.Snippet,
386
+ insertText: 'vision: "${1:Vision statement}"',
387
+ insertTextFormat: InsertTextFormat.Snippet,
388
+ documentation: '📝 Snippet: Define the strategic vision for this domain',
389
+ sortText: '0_snippet_vision'
390
+ });
391
+ }
392
+
393
+ if (!node.type) {
394
+ acceptor(context, {
395
+ label: '⚡ type',
396
+ kind: CompletionItemKind.Snippet,
397
+ insertText: 'type: ${1:Core}',
398
+ insertTextFormat: InsertTextFormat.Snippet,
399
+ documentation: '📝 Snippet: Classify as Core, Supporting, or Generic domain type',
400
+ sortText: '0_snippet_type'
401
+ });
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Add completions for ContextMap.
407
+ * Suggests relationship patterns and context references.
408
+ */
409
+ private addContextMapCompletions(
410
+ node: ast.ContextMap,
411
+ acceptor: CompletionAcceptor,
412
+ context: CompletionContext
413
+ ): void {
414
+ // Suggest contains if no contexts yet
415
+ if (node.boundedContexts.length === 0) {
416
+ acceptor(context, {
417
+ label: 'contains',
418
+ kind: CompletionItemKind.Keyword,
419
+ insertText: 'contains ${1:Context1}, ${2:Context2}',
420
+ insertTextFormat: InsertTextFormat.Snippet,
421
+ documentation: 'Add bounded contexts to this map',
422
+ sortText: '0_contains'
423
+ });
424
+ }
425
+
426
+ // Always suggest relationship snippet
427
+ acceptor(context, {
428
+ label: 'relationship (simple)',
429
+ kind: CompletionItemKind.Snippet,
430
+ insertText: '${1:Context1} -> ${2:Context2}',
431
+ insertTextFormat: InsertTextFormat.Snippet,
432
+ documentation: 'Add a simple upstream-downstream relationship',
433
+ sortText: '1_relationship_simple'
434
+ });
435
+
436
+ acceptor(context, {
437
+ label: 'relationship (with patterns)',
438
+ kind: CompletionItemKind.Snippet,
439
+ insertText: '[${1|OHS,PL,ACL,CF,P,SK|}] ${2:Context1} -> [${3|OHS,PL,ACL,CF,P,SK|}] ${4:Context2}',
440
+ insertTextFormat: InsertTextFormat.Snippet,
441
+ documentation: 'Add a relationship with integration patterns',
442
+ sortText: '1_relationship_patterns'
443
+ });
444
+ }
445
+
446
+ /**
447
+ * Add completions for DomainMap.
448
+ * Suggests domain references.
449
+ */
450
+ private addDomainMapCompletions(
451
+ node: ast.DomainMap,
452
+ acceptor: CompletionAcceptor,
453
+ context: CompletionContext
454
+ ): void {
455
+ // Suggest contains if no domains yet
456
+ if (node.domains.length === 0) {
457
+ acceptor(context, {
458
+ label: 'contains',
459
+ kind: CompletionItemKind.Keyword,
460
+ insertText: 'contains ${1:Domain1}, ${2:Domain2}',
461
+ insertTextFormat: InsertTextFormat.Snippet,
462
+ documentation: 'Add domains to this map',
463
+ sortText: '0_contains'
464
+ });
465
+ }
466
+ }
467
+
468
+ /**
469
+ * Add completions for relationships.
470
+ * Provides integration patterns and relationship types.
471
+ */
472
+ private addRelationshipCompletions(
473
+ acceptor: CompletionAcceptor,
474
+ context: CompletionContext
475
+ ): void {
476
+ // Integration pattern completions
477
+ const patterns = [
478
+ { label: 'OHS (Open Host Service)', insertText: '[OHS]', doc: 'Open Host Service pattern' },
479
+ { label: 'PL (Published Language)', insertText: '[PL]', doc: 'Published Language pattern' },
480
+ { label: 'ACL (Anti-Corruption Layer)', insertText: '[ACL]', doc: 'Anti-Corruption Layer pattern' },
481
+ { label: 'CF (Conformist)', insertText: '[CF]', doc: 'Conformist pattern' },
482
+ { label: 'P (Partnership)', insertText: '[P]', doc: 'Partnership pattern' },
483
+ { label: 'SK (Shared Kernel)', insertText: '[SK]', doc: 'Shared Kernel pattern' }
484
+ ];
485
+
486
+ for (const pattern of patterns) {
487
+ acceptor(context, {
488
+ label: pattern.label,
489
+ kind: CompletionItemKind.EnumMember,
490
+ insertText: pattern.insertText,
491
+ documentation: pattern.doc,
492
+ sortText: `0_${pattern.label}`
493
+ });
494
+ }
495
+
496
+ // Relationship arrow completions
497
+ const arrows = [
498
+ { label: '->', doc: 'Upstream to downstream' },
499
+ { label: '<-', doc: 'Downstream to upstream' },
500
+ { label: '<->', doc: 'Bidirectional/Partnership' },
501
+ { label: '><', doc: 'Separate Ways' }
502
+ ];
503
+
504
+ for (const arrow of arrows) {
505
+ acceptor(context, {
506
+ label: arrow.label,
507
+ kind: CompletionItemKind.Operator,
508
+ insertText: arrow.label,
509
+ documentation: arrow.doc,
510
+ sortText: `1_${arrow.label}`
511
+ });
512
+ }
513
+ }
514
+ }
@@ -0,0 +1,51 @@
1
+ import type { AstNode } from "langium";
2
+ import { AbstractFormatter, Formatting } from "langium/lsp";
3
+ import * as ast from '../generated/ast.js';
4
+
5
+ /**
6
+ * Provides formatting for DomainLang documents.
7
+ * Handles indentation and newlines for block-based constructs.
8
+ */
9
+ export class DomainLangFormatter extends AbstractFormatter {
10
+
11
+ protected format(node: AstNode): void {
12
+ // Namespace declarations
13
+ if (ast.isNamespaceDeclaration(node)) {
14
+ this.formatBlock(node);
15
+ }
16
+
17
+ // Domain declarations
18
+ if (ast.isDomain(node)) {
19
+ this.formatBlock(node);
20
+ }
21
+
22
+ // Bounded contexts
23
+ if (ast.isBoundedContext(node)) {
24
+ this.formatBlock(node);
25
+ }
26
+
27
+ // Context maps
28
+ if (ast.isContextMap(node)) {
29
+ this.formatBlock(node);
30
+ }
31
+
32
+ // Domain maps
33
+ if (ast.isDomainMap(node)) {
34
+ this.formatBlock(node);
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Formats a block node with standard indentation and newlines.
40
+ *
41
+ * @param node - The AST node to format
42
+ */
43
+ private formatBlock(node: AstNode): void {
44
+ const formatter = this.getNodeFormatter(node);
45
+ const open = formatter.keyword('{');
46
+ const close = formatter.keyword('}');
47
+
48
+ formatter.interior(open, close).prepend(Formatting.indent());
49
+ close.prepend(Formatting.newLine());
50
+ }
51
+ }
@@ -0,0 +1,56 @@
1
+ /******************************************************************************
2
+ * Copyright 2021 TypeFox GmbH
3
+ * This program and the accompanying materials are made available under the
4
+ * terms of the MIT License, which is available in the project root.
5
+ ******************************************************************************/
6
+
7
+ // domain-lang-naming.ts
8
+ // Provides utilities for generating fully qualified names (FQN) for domain language elements, supporting nested namespaces and disambiguation.
9
+
10
+ import type { Container, NamespaceDeclaration } from '../generated/ast.js';
11
+ import { isModel, isNamespaceDeclaration } from '../generated/ast.js';
12
+
13
+ /**
14
+ * Joins parent and child names into a fully qualified name, using '.' as a separator.
15
+ * Ensures no leading or trailing dots and supports arbitrary nesting.
16
+ * @param parent - The parent name or empty string
17
+ * @param child - The child name
18
+ * @returns The fully qualified name
19
+ */
20
+ export function joinQualifiedName(parent: string, child: string): string {
21
+ return parent ? `${parent}.${child}` : child;
22
+ }
23
+
24
+ /**
25
+ * Recursively computes the fully qualified name for a child element within nested namespaces.
26
+ * @param namespace - The current namespace declaration
27
+ * @param childName - The name of the child element
28
+ * @returns The fully qualified name as a string
29
+ */
30
+ export function toQualifiedName(namespace: NamespaceDeclaration, childName: string): string {
31
+ return isNamespaceDeclaration(namespace.$container)
32
+ ? joinQualifiedName(toQualifiedName(namespace.$container, namespace.name), childName)
33
+ : joinQualifiedName(namespace.name, childName);
34
+ }
35
+
36
+ /**
37
+ * Provides qualified name computation for domain language elements, supporting nested namespaces and models.
38
+ * Used for FQN disambiguation and reference resolution.
39
+ */
40
+ export class QualifiedNameProvider {
41
+ /**
42
+ * Computes the qualified name for a given qualifier and name.
43
+ * @param qualifier - The parent container (Model, NamespaceDeclaration, or string)
44
+ * @param name - The simple name of the element
45
+ * @returns The fully qualified name as a string
46
+ */
47
+ getQualifiedName(qualifier: Container | string, name: string): string {
48
+ let prefix = isModel(qualifier) ? '' : qualifier;
49
+ if (isNamespaceDeclaration(prefix)) {
50
+ prefix = isNamespaceDeclaration(prefix.$container)
51
+ ? this.getQualifiedName(prefix.$container, prefix.name)
52
+ : prefix.name;
53
+ }
54
+ return prefix ? `${prefix}.${name}` : name;
55
+ }
56
+ }