@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,679 @@
1
+ /**
2
+ * Query and QueryBuilder implementation for the Model Query SDK.
3
+ * Provides fluent, lazy evaluation of model queries.
4
+ */
5
+ import { AstUtils } from 'langium';
6
+ import { isBoundedContext, isClassification, isContextMap, isDomain, isDomainMap, isModel, isNamespaceDeclaration, isTeam, isThisRef, } from '../generated/ast.js';
7
+ import { QualifiedNameProvider } from '../lsp/domain-lang-naming.js';
8
+ import { buildIndexes } from './indexes.js';
9
+ import { metadataAsMap, effectiveClassification, effectiveTeam, } from './resolution.js';
10
+ import { isDownstreamPattern, isUpstreamPattern, matchesPattern } from './patterns.js';
11
+ /**
12
+ * Tracks which models have been augmented to avoid redundant augmentation.
13
+ * Uses WeakSet to allow garbage collection of unused models.
14
+ */
15
+ const augmentedModels = new WeakSet();
16
+ /**
17
+ * Ensures a model is augmented with SDK properties.
18
+ * Idempotent - safe to call multiple times.
19
+ *
20
+ * @param model - Model to ensure is augmented
21
+ */
22
+ function ensureAugmented(model) {
23
+ if (!augmentedModels.has(model)) {
24
+ augmentModelInternal(model);
25
+ augmentedModels.add(model);
26
+ }
27
+ }
28
+ /**
29
+ * Creates a Query instance from a Model node.
30
+ * Zero-copy operation for already-linked AST (used in LSP/validation).
31
+ *
32
+ * Automatically augments the AST with resolved properties on first access.
33
+ *
34
+ * @param model - Root Model node
35
+ * @returns Query interface for model traversal
36
+ */
37
+ export function fromModel(model) {
38
+ ensureAugmented(model);
39
+ return new QueryImpl(model);
40
+ }
41
+ /**
42
+ * Creates a Query instance from a LangiumDocument.
43
+ * Zero-copy operation for already-linked AST (used in LSP providers).
44
+ *
45
+ * Automatically augments the AST with resolved properties on first access.
46
+ *
47
+ * @param document - LangiumDocument containing a Model
48
+ * @returns Query interface for model traversal
49
+ */
50
+ export function fromDocument(document) {
51
+ const model = document.parseResult.value;
52
+ ensureAugmented(model);
53
+ return new QueryImpl(model);
54
+ }
55
+ /**
56
+ * Creates a Query instance from DomainLangServices and document URI.
57
+ * Zero-copy operation for already-linked AST (used when only services available).
58
+ *
59
+ * Automatically augments the AST with resolved properties on first access.
60
+ *
61
+ * @param services - DomainLangServices instance
62
+ * @param documentUri - URI of the document to query
63
+ * @returns Query interface for model traversal
64
+ * @throws Error if document not found or not a Model
65
+ */
66
+ export function fromServices(services, documentUri) {
67
+ const document = services.shared.workspace.LangiumDocuments.getDocument(documentUri);
68
+ if (!document) {
69
+ throw new Error(`Document not found: ${documentUri.toString()}`);
70
+ }
71
+ const model = document.parseResult.value;
72
+ if (!isModel(model)) {
73
+ throw new Error(`Document root is not a Model: ${documentUri.toString()}`);
74
+ }
75
+ ensureAugmented(model);
76
+ return new QueryImpl(model);
77
+ }
78
+ /**
79
+ * Implementation of Query interface.
80
+ * Lazily builds indexes on first access.
81
+ */
82
+ class QueryImpl {
83
+ constructor(model) {
84
+ this.model = model;
85
+ this.fqnProvider = new QualifiedNameProvider();
86
+ }
87
+ /**
88
+ * Lazily builds and caches indexes on first access.
89
+ */
90
+ getIndexes() {
91
+ if (!this.indexes) {
92
+ this.indexes = buildIndexes(this.model);
93
+ }
94
+ return this.indexes;
95
+ }
96
+ domains() {
97
+ // Use generator for lazy iteration per PRS requirement
98
+ const model = this.model;
99
+ function* domainIterator() {
100
+ for (const node of AstUtils.streamAllContents(model)) {
101
+ if (isDomain(node)) {
102
+ yield node;
103
+ }
104
+ }
105
+ }
106
+ return new QueryBuilderImpl(domainIterator(), this.fqnProvider);
107
+ }
108
+ boundedContexts() {
109
+ // Use generator for lazy iteration per PRS requirement
110
+ const model = this.model;
111
+ function* bcIterator() {
112
+ for (const node of AstUtils.streamAllContents(model)) {
113
+ if (isBoundedContext(node)) {
114
+ yield node;
115
+ }
116
+ }
117
+ }
118
+ return new BcQueryBuilderImpl(bcIterator(), this.fqnProvider, this.getIndexes());
119
+ }
120
+ teams() {
121
+ // Use generator for lazy iteration
122
+ const model = this.model;
123
+ function* teamIterator() {
124
+ for (const node of AstUtils.streamAllContents(model)) {
125
+ if (isTeam(node)) {
126
+ yield node;
127
+ }
128
+ }
129
+ }
130
+ return new QueryBuilderImpl(teamIterator(), this.fqnProvider);
131
+ }
132
+ classifications() {
133
+ // Use generator for lazy iteration
134
+ const model = this.model;
135
+ function* classIterator() {
136
+ for (const node of AstUtils.streamAllContents(model)) {
137
+ if (isClassification(node)) {
138
+ yield node;
139
+ }
140
+ }
141
+ }
142
+ return new QueryBuilderImpl(classIterator(), this.fqnProvider);
143
+ }
144
+ relationships() {
145
+ // Use generator for lazy iteration - combines BC and ContextMap relationships
146
+ return new QueryBuilderImpl(this.iterateRelationships(), this.fqnProvider);
147
+ }
148
+ /** @internal Generator for relationship iteration */
149
+ *iterateRelationships() {
150
+ // Collect relationships defined on bounded contexts
151
+ for (const node of AstUtils.streamAllContents(this.model)) {
152
+ if (isBoundedContext(node)) {
153
+ for (const rel of node.relationships) {
154
+ const view = this.createRelationshipView(rel, node, 'BoundedContext');
155
+ if (view) {
156
+ yield view;
157
+ }
158
+ }
159
+ }
160
+ }
161
+ // Collect from ContextMap.relationships
162
+ for (const node of AstUtils.streamAllContents(this.model)) {
163
+ if (isContextMap(node)) {
164
+ for (const rel of node.relationships) {
165
+ const view = this.createRelationshipView(rel, undefined, 'ContextMap');
166
+ if (view) {
167
+ yield view;
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
173
+ contextMaps() {
174
+ const model = this.model;
175
+ function* cmapIterator() {
176
+ for (const node of AstUtils.streamAllContents(model)) {
177
+ if (isContextMap(node)) {
178
+ yield node;
179
+ }
180
+ }
181
+ }
182
+ return new QueryBuilderImpl(cmapIterator(), this.fqnProvider);
183
+ }
184
+ domainMaps() {
185
+ const model = this.model;
186
+ function* dmapIterator() {
187
+ for (const node of AstUtils.streamAllContents(model)) {
188
+ if (isDomainMap(node)) {
189
+ yield node;
190
+ }
191
+ }
192
+ }
193
+ return new QueryBuilderImpl(dmapIterator(), this.fqnProvider);
194
+ }
195
+ namespaces() {
196
+ const model = this.model;
197
+ function* nsIterator() {
198
+ for (const node of AstUtils.streamAllContents(model)) {
199
+ if (isNamespaceDeclaration(node)) {
200
+ yield node;
201
+ }
202
+ }
203
+ }
204
+ return new QueryBuilderImpl(nsIterator(), this.fqnProvider);
205
+ }
206
+ byFqn(fqn) {
207
+ return this.getIndexes().byFqn.get(fqn);
208
+ }
209
+ domain(name) {
210
+ // Try FQN lookup first
211
+ const byFqn = this.byFqn(name);
212
+ if (byFqn) {
213
+ return byFqn;
214
+ }
215
+ // Fallback to simple name lookup
216
+ const nodes = this.getIndexes().byName.get(name) ?? [];
217
+ return nodes.find(isDomain);
218
+ }
219
+ boundedContext(name) {
220
+ // Try FQN lookup first
221
+ const byFqn = this.byFqn(name);
222
+ if (byFqn) {
223
+ return byFqn;
224
+ }
225
+ // Fallback to simple name lookup
226
+ const nodes = this.getIndexes().byName.get(name) ?? [];
227
+ return nodes.find(isBoundedContext);
228
+ }
229
+ bc(name) {
230
+ return this.boundedContext(name);
231
+ }
232
+ team(name) {
233
+ const nodes = this.getIndexes().byName.get(name) ?? [];
234
+ return nodes.find(isTeam);
235
+ }
236
+ fqn(node) {
237
+ if ('name' in node && typeof node.name === 'string' && node.$container) {
238
+ const container = node.$container;
239
+ if (isModel(container) || isNamespaceDeclaration(container)) {
240
+ return this.fqnProvider.getQualifiedName(container, node.name);
241
+ }
242
+ }
243
+ return '';
244
+ }
245
+ /**
246
+ * Creates a RelationshipView from a Relationship AST node.
247
+ * Resolves 'this' references to the containing BoundedContext.
248
+ */
249
+ createRelationshipView(rel, containingBc, source) {
250
+ const left = this.resolveContextRef(rel.left, containingBc);
251
+ const right = this.resolveContextRef(rel.right, containingBc);
252
+ if (!left || !right) {
253
+ return undefined;
254
+ }
255
+ return {
256
+ left,
257
+ right,
258
+ arrow: rel.arrow,
259
+ leftPatterns: rel.leftPatterns,
260
+ rightPatterns: rel.rightPatterns,
261
+ type: rel.type,
262
+ inferredType: this.inferRelationshipType(rel),
263
+ source,
264
+ astNode: rel,
265
+ };
266
+ }
267
+ /**
268
+ * Resolves a BoundedContextRef to a BoundedContext.
269
+ * Handles 'this' references by using the containing BoundedContext.
270
+ */
271
+ resolveContextRef(ref, containingBc) {
272
+ if (isThisRef(ref)) {
273
+ return containingBc;
274
+ }
275
+ return ref.link?.ref;
276
+ }
277
+ /**
278
+ * Infers relationship type from integration patterns.
279
+ * Simple heuristic based on common DDD pattern combinations.
280
+ */
281
+ inferRelationshipType(rel) {
282
+ const leftPatterns = rel.leftPatterns;
283
+ const rightPatterns = rel.rightPatterns;
284
+ // Partnership: Bidirectional with P or SK
285
+ if (rel.arrow === '<->' && (leftPatterns.includes('P') || leftPatterns.includes('SK'))) {
286
+ return 'Partnership';
287
+ }
288
+ // Shared Kernel: SK pattern
289
+ if (leftPatterns.includes('SK') || rightPatterns.includes('SK')) {
290
+ return 'SharedKernel';
291
+ }
292
+ // Customer-Supplier: OHS + CF
293
+ if (leftPatterns.includes('OHS') && rightPatterns.includes('CF')) {
294
+ return 'CustomerSupplier';
295
+ }
296
+ // Upstream-Downstream: directional arrow
297
+ if (rel.arrow === '->') {
298
+ return 'UpstreamDownstream';
299
+ }
300
+ // Separate Ways
301
+ if (rel.arrow === '><') {
302
+ return 'SeparateWays';
303
+ }
304
+ return undefined;
305
+ }
306
+ }
307
+ /**
308
+ * Base implementation of QueryBuilder with lazy iteration.
309
+ * Predicates are chained and only evaluated during iteration.
310
+ */
311
+ class QueryBuilderImpl {
312
+ constructor(items, fqnProvider, predicates = []) {
313
+ this.fqnProvider = fqnProvider;
314
+ this.sourceItems = items;
315
+ this.predicateList = predicates;
316
+ }
317
+ where(predicate) {
318
+ return new QueryBuilderImpl(this.sourceItems, this.fqnProvider, [...this.predicateList, predicate]);
319
+ }
320
+ withName(pattern) {
321
+ const regex = typeof pattern === 'string' ? new RegExp(`^${escapeRegex(pattern)}$`) : pattern;
322
+ return this.where((item) => {
323
+ const node = item;
324
+ if ('name' in node && typeof node.name === 'string') {
325
+ return regex.test(node.name);
326
+ }
327
+ return false;
328
+ });
329
+ }
330
+ withFqn(pattern) {
331
+ const regex = typeof pattern === 'string' ? new RegExp(`^${escapeRegex(pattern)}$`) : pattern;
332
+ return this.where((item) => {
333
+ const node = item;
334
+ if ('name' in node && typeof node.name === 'string' && node.$container) {
335
+ const container = node.$container;
336
+ if (isModel(container) || isNamespaceDeclaration(container)) {
337
+ const fqn = this.fqnProvider.getQualifiedName(container, node.name);
338
+ return regex.test(fqn);
339
+ }
340
+ }
341
+ return false;
342
+ });
343
+ }
344
+ first() {
345
+ for (const item of this) {
346
+ return item;
347
+ }
348
+ return undefined;
349
+ }
350
+ toArray() {
351
+ return Array.from(this);
352
+ }
353
+ count() {
354
+ let count = 0;
355
+ for (const _ of this) {
356
+ count++;
357
+ }
358
+ return count;
359
+ }
360
+ *[Symbol.iterator]() {
361
+ for (const item of this.sourceItems) {
362
+ if (this.predicateList.every(p => p(item))) {
363
+ yield item;
364
+ }
365
+ }
366
+ }
367
+ }
368
+ /**
369
+ * BoundedContext-specific QueryBuilder with domain filters.
370
+ * Supports indexed lookups for performance when filters allow.
371
+ */
372
+ class BcQueryBuilderImpl extends QueryBuilderImpl {
373
+ constructor(items, fqnProvider, indexes, predicates = []) {
374
+ super(items, fqnProvider, predicates);
375
+ this.indexes = indexes;
376
+ }
377
+ where(predicate) {
378
+ return new BcQueryBuilderImpl(this.sourceItems, this.fqnProvider, this.indexes, [...this.predicateList, predicate]);
379
+ }
380
+ withName(pattern) {
381
+ return super.withName(pattern);
382
+ }
383
+ withFqn(pattern) {
384
+ return super.withFqn(pattern);
385
+ }
386
+ inDomain(domain) {
387
+ const domainName = typeof domain === 'string' ? domain : domain.name;
388
+ return this.where(bc => bc.domain?.ref?.name === domainName);
389
+ }
390
+ withTeam(team) {
391
+ const teamName = typeof team === 'string' ? team : team.name;
392
+ // Use index for initial filtering if no predicates yet
393
+ if (this.predicateList.length === 0) {
394
+ const indexed = this.indexes.byTeam.get(teamName) ?? [];
395
+ return new BcQueryBuilderImpl(indexed, this.fqnProvider, this.indexes);
396
+ }
397
+ // Add predicate to existing chain
398
+ return this.where(bc => effectiveTeam(bc)?.name === teamName);
399
+ }
400
+ withClassification(classification) {
401
+ const classificationName = typeof classification === 'string' ? classification : classification.name;
402
+ // Use index for initial filtering if no predicates yet
403
+ if (this.predicateList.length === 0) {
404
+ const indexed = this.indexes.byClassification.get(classificationName) ?? [];
405
+ return new BcQueryBuilderImpl(indexed, this.fqnProvider, this.indexes);
406
+ }
407
+ // Add predicate to existing chain
408
+ return this.where(bc => effectiveClassification(bc)?.name === classificationName);
409
+ }
410
+ withMetadata(key, value) {
411
+ // Use index for initial filtering if no predicates yet and no value specified
412
+ if (this.predicateList.length === 0 && value === undefined) {
413
+ const indexed = this.indexes.byMetadataKey.get(key) ?? [];
414
+ return new BcQueryBuilderImpl(indexed, this.fqnProvider, this.indexes);
415
+ }
416
+ // Add predicate to existing chain
417
+ return this.where(bc => {
418
+ const metadata = metadataAsMap(bc);
419
+ const metaValue = metadata.get(key);
420
+ if (metaValue === undefined) {
421
+ return false;
422
+ }
423
+ return value === undefined || metaValue === value;
424
+ });
425
+ }
426
+ }
427
+ /**
428
+ * Escapes special regex characters in a string.
429
+ */
430
+ function escapeRegex(str) {
431
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
432
+ }
433
+ /**
434
+ * Augments BoundedContext instances with SDK-resolved properties.
435
+ * Called during model loading to enrich the AST.
436
+ *
437
+ * Properties use natural names (not sdk* prefix) per PRS:
438
+ * "Properties are discoverable in IDE autocomplete. The SDK enriches the AST
439
+ * during load, so `bc.classification` just works—no imports needed."
440
+ *
441
+ * Note: We use getters to avoid computing values until accessed.
442
+ * Note: We use Object.defineProperty to avoid modifying the original interface.
443
+ *
444
+ * @param bc - BoundedContext to augment
445
+ */
446
+ export function augmentBoundedContext(bc) {
447
+ const fqnProvider = new QualifiedNameProvider();
448
+ // Define computed properties with getters for lazy evaluation
449
+ // Only include properties that add value beyond direct AST access:
450
+ // - effectiveClassification/effectiveTeam: array precedence resolution
451
+ // - metadataMap: array to Map conversion
452
+ // - fqn: computed qualified name
453
+ // - helper methods: hasClassification, hasTeam, hasMetadata
454
+ Object.defineProperties(bc, {
455
+ effectiveClassification: {
456
+ get: () => effectiveClassification(bc),
457
+ enumerable: true,
458
+ configurable: true,
459
+ },
460
+ effectiveTeam: {
461
+ get: () => effectiveTeam(bc),
462
+ enumerable: true,
463
+ configurable: true,
464
+ },
465
+ metadataMap: {
466
+ get: () => metadataAsMap(bc),
467
+ enumerable: true,
468
+ configurable: true,
469
+ },
470
+ fqn: {
471
+ get: () => {
472
+ if (bc.$container && (isModel(bc.$container) || isNamespaceDeclaration(bc.$container))) {
473
+ return fqnProvider.getQualifiedName(bc.$container, bc.name);
474
+ }
475
+ return bc.name;
476
+ },
477
+ enumerable: true,
478
+ configurable: true,
479
+ },
480
+ // Helper methods
481
+ hasClassification: {
482
+ value: (name) => {
483
+ const classification = effectiveClassification(bc);
484
+ if (!classification)
485
+ return false;
486
+ const targetName = typeof name === 'string' ? name : name?.name;
487
+ if (!targetName)
488
+ return false;
489
+ return classification.name === targetName;
490
+ },
491
+ enumerable: false,
492
+ configurable: true,
493
+ },
494
+ hasTeam: {
495
+ value: (name) => {
496
+ const team = effectiveTeam(bc);
497
+ if (!team)
498
+ return false;
499
+ const targetName = typeof name === 'string' ? name : name?.name;
500
+ if (!targetName)
501
+ return false;
502
+ return team.name === targetName;
503
+ },
504
+ enumerable: false,
505
+ configurable: true,
506
+ },
507
+ hasMetadata: {
508
+ value: (key, value) => {
509
+ const metadata = metadataAsMap(bc);
510
+ const metaValue = metadata.get(key);
511
+ if (metaValue === undefined)
512
+ return false;
513
+ return value === undefined || metaValue === value;
514
+ },
515
+ enumerable: false,
516
+ configurable: true,
517
+ },
518
+ });
519
+ }
520
+ /**
521
+ * Augments Domain instances with SDK-resolved properties.
522
+ * Called during model loading to enrich the AST.
523
+ *
524
+ * Only includes properties that add value beyond direct AST access:
525
+ * - fqn: computed qualified name
526
+ * - hasType: helper method
527
+ *
528
+ * Direct access (no augmentation needed):
529
+ * - domain.description
530
+ * - domain.vision
531
+ * - domain.type?.ref
532
+ *
533
+ * @param domain - Domain to augment
534
+ */
535
+ export function augmentDomain(domain) {
536
+ const fqnProvider = new QualifiedNameProvider();
537
+ Object.defineProperties(domain, {
538
+ fqn: {
539
+ get: () => {
540
+ if (domain.$container && (isModel(domain.$container) || isNamespaceDeclaration(domain.$container))) {
541
+ return fqnProvider.getQualifiedName(domain.$container, domain.name);
542
+ }
543
+ return domain.name;
544
+ },
545
+ enumerable: true,
546
+ configurable: true,
547
+ },
548
+ // Helper methods
549
+ hasType: {
550
+ value: (name) => {
551
+ const type = domain.type?.ref;
552
+ if (!type)
553
+ return false;
554
+ const targetName = typeof name === 'string' ? name : name?.name;
555
+ if (!targetName)
556
+ return false;
557
+ return type.name === targetName;
558
+ },
559
+ enumerable: false,
560
+ configurable: true,
561
+ },
562
+ });
563
+ }
564
+ /**
565
+ * Augments Relationship instances with SDK helper methods.
566
+ * Called during model loading to enrich the AST.
567
+ *
568
+ * @param rel - Relationship to augment
569
+ * @param containingBc - BoundedContext containing this relationship (for 'this' resolution)
570
+ */
571
+ export function augmentRelationship(rel, containingBc) {
572
+ Object.defineProperties(rel, {
573
+ leftContextName: {
574
+ get: () => {
575
+ if (isThisRef(rel.left)) {
576
+ return containingBc?.name ?? 'this';
577
+ }
578
+ return rel.left.link?.ref?.name ?? '';
579
+ },
580
+ enumerable: true,
581
+ configurable: true,
582
+ },
583
+ rightContextName: {
584
+ get: () => {
585
+ if (isThisRef(rel.right)) {
586
+ return containingBc?.name ?? 'this';
587
+ }
588
+ return rel.right.link?.ref?.name ?? '';
589
+ },
590
+ enumerable: true,
591
+ configurable: true,
592
+ },
593
+ isBidirectional: {
594
+ get: () => rel.arrow === '<->',
595
+ enumerable: true,
596
+ configurable: true,
597
+ },
598
+ // Helper methods for pattern matching (type-safe, no magic strings)
599
+ hasPattern: {
600
+ value: (pattern) => {
601
+ return rel.leftPatterns.some(p => matchesPattern(p, pattern)) ||
602
+ rel.rightPatterns.some(p => matchesPattern(p, pattern));
603
+ },
604
+ enumerable: false,
605
+ configurable: true,
606
+ },
607
+ hasLeftPattern: {
608
+ value: (pattern) => {
609
+ return rel.leftPatterns.some(p => matchesPattern(p, pattern));
610
+ },
611
+ enumerable: false,
612
+ configurable: true,
613
+ },
614
+ hasRightPattern: {
615
+ value: (pattern) => {
616
+ return rel.rightPatterns.some(p => matchesPattern(p, pattern));
617
+ },
618
+ enumerable: false,
619
+ configurable: true,
620
+ },
621
+ isUpstream: {
622
+ value: (side) => {
623
+ const patterns = side === 'left' ? rel.leftPatterns : rel.rightPatterns;
624
+ return patterns.some(p => isUpstreamPattern(p));
625
+ },
626
+ enumerable: false,
627
+ configurable: true,
628
+ },
629
+ isDownstream: {
630
+ value: (side) => {
631
+ const patterns = side === 'left' ? rel.leftPatterns : rel.rightPatterns;
632
+ return patterns.some(p => isDownstreamPattern(p));
633
+ },
634
+ enumerable: false,
635
+ configurable: true,
636
+ },
637
+ });
638
+ }
639
+ /**
640
+ * Internal implementation of model augmentation.
641
+ * Called by ensureAugmented() which tracks augmentation state.
642
+ *
643
+ * @param model - Root Model node to augment
644
+ */
645
+ function augmentModelInternal(model) {
646
+ for (const node of AstUtils.streamAllContents(model)) {
647
+ if (isBoundedContext(node)) {
648
+ augmentBoundedContext(node);
649
+ // Augment relationships inside this bounded context
650
+ for (const rel of node.relationships) {
651
+ augmentRelationship(rel, node);
652
+ }
653
+ }
654
+ else if (isDomain(node)) {
655
+ augmentDomain(node);
656
+ }
657
+ else if (isContextMap(node)) {
658
+ // Augment relationships in context maps (no containing BC)
659
+ for (const rel of node.relationships) {
660
+ augmentRelationship(rel, undefined);
661
+ }
662
+ }
663
+ }
664
+ }
665
+ /**
666
+ * Augments all AST nodes in a model with SDK-resolved properties.
667
+ *
668
+ * This function walks the entire AST and adds lazy getters for resolved
669
+ * properties like `effectiveClassification`, `effectiveTeam`, etc.
670
+ *
671
+ * Idempotent - safe to call multiple times on the same model.
672
+ * Automatically called by `fromModel()`, `fromDocument()`, and `fromServices()`.
673
+ *
674
+ * @param model - Root Model node to augment
675
+ */
676
+ export function augmentModel(model) {
677
+ ensureAugmented(model);
678
+ }
679
+ //# sourceMappingURL=query.js.map