@domainlang/language 0.1.20

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 (212) hide show
  1. package/README.md +163 -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 +57 -0
  6. package/out/domain-lang-module.js +67 -0
  7. package/out/domain-lang-module.js.map +1 -0
  8. package/out/generated/ast.d.ts +759 -0
  9. package/out/generated/ast.js +556 -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 +2407 -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 +16 -0
  18. package/out/index.js +22 -0
  19. package/out/index.js.map +1 -0
  20. package/out/lsp/domain-lang-code-actions.d.ts +55 -0
  21. package/out/lsp/domain-lang-code-actions.js +143 -0
  22. package/out/lsp/domain-lang-code-actions.js.map +1 -0
  23. package/out/lsp/domain-lang-completion.d.ts +37 -0
  24. package/out/lsp/domain-lang-completion.js +452 -0
  25. package/out/lsp/domain-lang-completion.js.map +1 -0
  26. package/out/lsp/domain-lang-formatter.d.ts +15 -0
  27. package/out/lsp/domain-lang-formatter.js +43 -0
  28. package/out/lsp/domain-lang-formatter.js.map +1 -0
  29. package/out/lsp/domain-lang-naming.d.ts +34 -0
  30. package/out/lsp/domain-lang-naming.js +49 -0
  31. package/out/lsp/domain-lang-naming.js.map +1 -0
  32. package/out/lsp/domain-lang-scope.d.ts +59 -0
  33. package/out/lsp/domain-lang-scope.js +102 -0
  34. package/out/lsp/domain-lang-scope.js.map +1 -0
  35. package/out/lsp/domain-lang-workspace-manager.d.ts +21 -0
  36. package/out/lsp/domain-lang-workspace-manager.js +93 -0
  37. package/out/lsp/domain-lang-workspace-manager.js.map +1 -0
  38. package/out/lsp/hover/ddd-pattern-explanations.d.ts +50 -0
  39. package/out/lsp/hover/ddd-pattern-explanations.js +196 -0
  40. package/out/lsp/hover/ddd-pattern-explanations.js.map +1 -0
  41. package/out/lsp/hover/domain-lang-hover.d.ts +19 -0
  42. package/out/lsp/hover/domain-lang-hover.js +302 -0
  43. package/out/lsp/hover/domain-lang-hover.js.map +1 -0
  44. package/out/lsp/hover/domain-lang-keywords.d.ts +13 -0
  45. package/out/lsp/hover/domain-lang-keywords.js +47 -0
  46. package/out/lsp/hover/domain-lang-keywords.js.map +1 -0
  47. package/out/lsp/manifest-diagnostics.d.ts +82 -0
  48. package/out/lsp/manifest-diagnostics.js +230 -0
  49. package/out/lsp/manifest-diagnostics.js.map +1 -0
  50. package/out/main-browser.d.ts +1 -0
  51. package/out/main-browser.js +11 -0
  52. package/out/main-browser.js.map +1 -0
  53. package/out/main.d.ts +1 -0
  54. package/out/main.js +74 -0
  55. package/out/main.js.map +1 -0
  56. package/out/sdk/ast-augmentation.d.ts +136 -0
  57. package/out/sdk/ast-augmentation.js +62 -0
  58. package/out/sdk/ast-augmentation.js.map +1 -0
  59. package/out/sdk/index.d.ts +94 -0
  60. package/out/sdk/index.js +97 -0
  61. package/out/sdk/index.js.map +1 -0
  62. package/out/sdk/indexes.d.ts +16 -0
  63. package/out/sdk/indexes.js +97 -0
  64. package/out/sdk/indexes.js.map +1 -0
  65. package/out/sdk/loader-node.d.ts +51 -0
  66. package/out/sdk/loader-node.js +119 -0
  67. package/out/sdk/loader-node.js.map +1 -0
  68. package/out/sdk/loader.d.ts +49 -0
  69. package/out/sdk/loader.js +85 -0
  70. package/out/sdk/loader.js.map +1 -0
  71. package/out/sdk/patterns.d.ts +93 -0
  72. package/out/sdk/patterns.js +123 -0
  73. package/out/sdk/patterns.js.map +1 -0
  74. package/out/sdk/query.d.ts +90 -0
  75. package/out/sdk/query.js +679 -0
  76. package/out/sdk/query.js.map +1 -0
  77. package/out/sdk/resolution.d.ts +52 -0
  78. package/out/sdk/resolution.js +68 -0
  79. package/out/sdk/resolution.js.map +1 -0
  80. package/out/sdk/types.d.ts +280 -0
  81. package/out/sdk/types.js +8 -0
  82. package/out/sdk/types.js.map +1 -0
  83. package/out/services/dependency-analyzer.d.ts +58 -0
  84. package/out/services/dependency-analyzer.js +254 -0
  85. package/out/services/dependency-analyzer.js.map +1 -0
  86. package/out/services/dependency-resolver.d.ts +146 -0
  87. package/out/services/dependency-resolver.js +452 -0
  88. package/out/services/dependency-resolver.js.map +1 -0
  89. package/out/services/git-url-resolver.browser.d.ts +10 -0
  90. package/out/services/git-url-resolver.browser.js +19 -0
  91. package/out/services/git-url-resolver.browser.js.map +1 -0
  92. package/out/services/git-url-resolver.d.ts +158 -0
  93. package/out/services/git-url-resolver.js +416 -0
  94. package/out/services/git-url-resolver.js.map +1 -0
  95. package/out/services/governance-validator.d.ts +44 -0
  96. package/out/services/governance-validator.js +153 -0
  97. package/out/services/governance-validator.js.map +1 -0
  98. package/out/services/import-resolver.d.ts +77 -0
  99. package/out/services/import-resolver.js +240 -0
  100. package/out/services/import-resolver.js.map +1 -0
  101. package/out/services/performance-optimizer.d.ts +60 -0
  102. package/out/services/performance-optimizer.js +140 -0
  103. package/out/services/performance-optimizer.js.map +1 -0
  104. package/out/services/relationship-inference.d.ts +11 -0
  105. package/out/services/relationship-inference.js +98 -0
  106. package/out/services/relationship-inference.js.map +1 -0
  107. package/out/services/semver.d.ts +98 -0
  108. package/out/services/semver.js +195 -0
  109. package/out/services/semver.js.map +1 -0
  110. package/out/services/types.d.ts +340 -0
  111. package/out/services/types.js +46 -0
  112. package/out/services/types.js.map +1 -0
  113. package/out/services/workspace-manager.d.ts +123 -0
  114. package/out/services/workspace-manager.js +489 -0
  115. package/out/services/workspace-manager.js.map +1 -0
  116. package/out/syntaxes/domain-lang.monarch.d.ts +76 -0
  117. package/out/syntaxes/domain-lang.monarch.js +29 -0
  118. package/out/syntaxes/domain-lang.monarch.js.map +1 -0
  119. package/out/utils/import-utils.d.ts +49 -0
  120. package/out/utils/import-utils.js +128 -0
  121. package/out/utils/import-utils.js.map +1 -0
  122. package/out/validation/bounded-context.d.ts +11 -0
  123. package/out/validation/bounded-context.js +79 -0
  124. package/out/validation/bounded-context.js.map +1 -0
  125. package/out/validation/classification.d.ts +3 -0
  126. package/out/validation/classification.js +3 -0
  127. package/out/validation/classification.js.map +1 -0
  128. package/out/validation/constants.d.ts +180 -0
  129. package/out/validation/constants.js +235 -0
  130. package/out/validation/constants.js.map +1 -0
  131. package/out/validation/domain-lang-validator.d.ts +2 -0
  132. package/out/validation/domain-lang-validator.js +27 -0
  133. package/out/validation/domain-lang-validator.js.map +1 -0
  134. package/out/validation/domain.d.ts +11 -0
  135. package/out/validation/domain.js +63 -0
  136. package/out/validation/domain.js.map +1 -0
  137. package/out/validation/import.d.ts +68 -0
  138. package/out/validation/import.js +237 -0
  139. package/out/validation/import.js.map +1 -0
  140. package/out/validation/manifest.d.ts +144 -0
  141. package/out/validation/manifest.js +327 -0
  142. package/out/validation/manifest.js.map +1 -0
  143. package/out/validation/maps.d.ts +21 -0
  144. package/out/validation/maps.js +60 -0
  145. package/out/validation/maps.js.map +1 -0
  146. package/out/validation/metadata.d.ts +7 -0
  147. package/out/validation/metadata.js +16 -0
  148. package/out/validation/metadata.js.map +1 -0
  149. package/out/validation/model.d.ts +12 -0
  150. package/out/validation/model.js +29 -0
  151. package/out/validation/model.js.map +1 -0
  152. package/out/validation/relationships.d.ts +12 -0
  153. package/out/validation/relationships.js +94 -0
  154. package/out/validation/relationships.js.map +1 -0
  155. package/out/validation/shared.d.ts +6 -0
  156. package/out/validation/shared.js +12 -0
  157. package/out/validation/shared.js.map +1 -0
  158. package/package.json +110 -0
  159. package/src/ast-augmentation.ts +5 -0
  160. package/src/domain-lang-module.ts +112 -0
  161. package/src/domain-lang.langium +351 -0
  162. package/src/generated/ast.ts +986 -0
  163. package/src/generated/grammar.ts +2409 -0
  164. package/src/generated/module.ts +25 -0
  165. package/src/index.ts +24 -0
  166. package/src/lsp/domain-lang-code-actions.ts +189 -0
  167. package/src/lsp/domain-lang-completion.ts +514 -0
  168. package/src/lsp/domain-lang-formatter.ts +51 -0
  169. package/src/lsp/domain-lang-naming.ts +56 -0
  170. package/src/lsp/domain-lang-scope.ts +137 -0
  171. package/src/lsp/domain-lang-workspace-manager.ts +104 -0
  172. package/src/lsp/hover/ddd-pattern-explanations.ts +237 -0
  173. package/src/lsp/hover/domain-lang-hover.ts +338 -0
  174. package/src/lsp/hover/domain-lang-keywords.ts +50 -0
  175. package/src/lsp/manifest-diagnostics.ts +290 -0
  176. package/src/main-browser.ts +15 -0
  177. package/src/main.ts +85 -0
  178. package/src/sdk/README.md +297 -0
  179. package/src/sdk/ast-augmentation.ts +157 -0
  180. package/src/sdk/index.ts +126 -0
  181. package/src/sdk/indexes.ts +155 -0
  182. package/src/sdk/loader-node.ts +146 -0
  183. package/src/sdk/loader.ts +99 -0
  184. package/src/sdk/patterns.ts +147 -0
  185. package/src/sdk/query.ts +802 -0
  186. package/src/sdk/resolution.ts +78 -0
  187. package/src/sdk/types.ts +323 -0
  188. package/src/services/dependency-analyzer.ts +321 -0
  189. package/src/services/dependency-resolver.ts +551 -0
  190. package/src/services/git-url-resolver.browser.ts +26 -0
  191. package/src/services/git-url-resolver.ts +517 -0
  192. package/src/services/governance-validator.ts +177 -0
  193. package/src/services/import-resolver.ts +292 -0
  194. package/src/services/performance-optimizer.ts +170 -0
  195. package/src/services/relationship-inference.ts +121 -0
  196. package/src/services/semver.ts +213 -0
  197. package/src/services/types.ts +415 -0
  198. package/src/services/workspace-manager.ts +607 -0
  199. package/src/syntaxes/domain-lang.monarch.ts +29 -0
  200. package/src/utils/import-utils.ts +152 -0
  201. package/src/validation/bounded-context.ts +99 -0
  202. package/src/validation/classification.ts +5 -0
  203. package/src/validation/constants.ts +304 -0
  204. package/src/validation/domain-lang-validator.ts +33 -0
  205. package/src/validation/domain.ts +77 -0
  206. package/src/validation/import.ts +295 -0
  207. package/src/validation/manifest.ts +439 -0
  208. package/src/validation/maps.ts +76 -0
  209. package/src/validation/metadata.ts +18 -0
  210. package/src/validation/model.ts +37 -0
  211. package/src/validation/relationships.ts +154 -0
  212. package/src/validation/shared.ts +14 -0
@@ -0,0 +1,137 @@
1
+ // domain-lang-scope.ts
2
+ // Implements custom scope computation for the DomainLang DSL, supporting FQN disambiguation, nested groups, and cross-file references.
3
+
4
+ /****************************************************************************
5
+ * Copyright 2021 TypeFox GmbH
6
+ * This program and the accompanying materials are made available under the
7
+ * terms of the MIT License, which is available in the project root.
8
+ ***************************************************************************/
9
+
10
+ import type {
11
+ AstNode,
12
+ AstNodeDescription,
13
+ LangiumDocument,
14
+ LocalSymbols
15
+ } from 'langium';
16
+ import {
17
+ DefaultScopeComputation,
18
+ interruptAndCheck,
19
+ MultiMap,
20
+ AstUtils
21
+ } from 'langium';
22
+ import { CancellationToken } from 'vscode-jsonrpc';
23
+ import type { NamespaceDeclaration, Model, Container } from '../generated/ast.js';
24
+ import { isType, isNamespaceDeclaration } from '../generated/ast.js';
25
+ import { QualifiedNameProvider } from './domain-lang-naming.js';
26
+ import type { DomainLangServices } from '../domain-lang-module.js';
27
+
28
+ /**
29
+ * Computes the scope for DomainLang elements, supporting nested namespaces, FQN disambiguation, and cross-file references.
30
+ * Extends Langium's DefaultScopeComputation to provide custom export and local scope logic.
31
+ */
32
+ export class DomainLangScopeComputation extends DefaultScopeComputation {
33
+ qualifiedNameProvider: QualifiedNameProvider;
34
+
35
+ /**
36
+ * Constructs a new DomainLangScopeComputation with injected services.
37
+ * @param services - The DomainLangServices instance
38
+ */
39
+ constructor(services: DomainLangServices) {
40
+ super(services);
41
+ this.qualifiedNameProvider = services.references.QualifiedNameProvider;
42
+ }
43
+
44
+ /**
45
+ * Computes exported node descriptions for types, using fully qualified names for nested namespaces.
46
+ * @param document - The LangiumDocument to process
47
+ * @param cancelToken - Optional cancellation token
48
+ * @returns A promise resolving to an array of AstNodeDescription
49
+ */
50
+ override async collectExportedSymbols(document: LangiumDocument, cancelToken = CancellationToken.None): Promise<AstNodeDescription[]> {
51
+ const descr: AstNodeDescription[] = [];
52
+ for (const modelNode of AstUtils.streamAllContents(document.parseResult.value)) {
53
+ await interruptAndCheck(cancelToken);
54
+ if (isType(modelNode)) {
55
+ let name = this.nameProvider.getName(modelNode);
56
+ if (!name) {
57
+ // Defensive: skip unnamed types
58
+ continue;
59
+ }
60
+ if (isNamespaceDeclaration(modelNode.$container)) {
61
+ name = this.qualifiedNameProvider.getQualifiedName(modelNode.$container as NamespaceDeclaration, name);
62
+ }
63
+ descr.push(this.descriptions.createDescription(modelNode, name, document));
64
+ }
65
+ }
66
+ return descr;
67
+ }
68
+
69
+ /**
70
+ * Computes local scopes for all containers, recursively processing nested namespaces.
71
+ * @param document - The LangiumDocument to process
72
+ * @param cancelToken - Optional cancellation token
73
+ * @returns A promise resolving to a LocalSymbols map
74
+ */
75
+ override async collectLocalSymbols(document: LangiumDocument, cancelToken = CancellationToken.None): Promise<LocalSymbols> {
76
+ const model = document.parseResult.value as Model;
77
+ const scopes = new MultiMap<AstNode, AstNodeDescription>();
78
+ await this.processContainer(model, scopes, document, cancelToken);
79
+ return scopes;
80
+ }
81
+
82
+ /**
83
+ * Recursively processes a container and its children, adding local descriptions and qualified names.
84
+ * @param container - The container node (Model or NamespaceDeclaration)
85
+ * @param scopes - The LocalSymbols map to populate
86
+ * @param document - The LangiumDocument being processed
87
+ * @param cancelToken - Optional cancellation token
88
+ * @returns A promise resolving to an array of AstNodeDescription
89
+ */
90
+ protected async processContainer(
91
+ container: Container,
92
+ scopes: LocalSymbols,
93
+ document: LangiumDocument,
94
+ cancelToken: CancellationToken
95
+ ): Promise<AstNodeDescription[]> {
96
+ const localDescriptions: AstNodeDescription[] = [];
97
+ for (const element of container.children) {
98
+ await interruptAndCheck(cancelToken);
99
+ if (isType(element) && element.name) {
100
+ const description = this.descriptions.createDescription(element, element.name, document);
101
+ localDescriptions.push(description);
102
+ } else if (isNamespaceDeclaration(element)) {
103
+ const nestedDescriptions = await this.processContainer(element, scopes, document, cancelToken);
104
+ for (const description of nestedDescriptions) {
105
+ // Add qualified names to the container
106
+ const qualified = this.createQualifiedDescription(element, description, document);
107
+ localDescriptions.push(qualified);
108
+ }
109
+ }
110
+ }
111
+ // MultiMap implements LocalSymbols interface with add/addAll methods
112
+ (scopes as MultiMap<AstNode, AstNodeDescription>).addAll(container, localDescriptions);
113
+ return localDescriptions;
114
+ }
115
+
116
+ /**
117
+ * Creates a qualified AstNodeDescription for a node within a namespace.
118
+ *
119
+ * @param namespace - The NamespaceDeclaration containing the node
120
+ * @param description - The AstNodeDescription to qualify
121
+ * @param document - The LangiumDocument being processed
122
+ * @returns A new AstNodeDescription with a fully qualified name
123
+ *
124
+ * @example
125
+ * // For a Domain "Sales" in namespace "Shared"
126
+ * // Returns description with name "Shared.Sales"
127
+ */
128
+ protected createQualifiedDescription(
129
+ namespace: NamespaceDeclaration,
130
+ description: AstNodeDescription,
131
+ document: LangiumDocument
132
+ ): AstNodeDescription {
133
+ const name = this.qualifiedNameProvider.getQualifiedName(namespace.name, description.name);
134
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
135
+ return this.descriptions.createDescription(description.node!, name, document);
136
+ }
137
+ }
@@ -0,0 +1,104 @@
1
+ import path from 'node:path';
2
+ import YAML from 'yaml';
3
+ import { DefaultWorkspaceManager, URI, UriUtils, type FileSystemNode, type LangiumDocument, type LangiumSharedCoreServices, type WorkspaceFolder } from 'langium';
4
+ import type { CancellationToken } from 'vscode-languageserver-protocol';
5
+ import { ensureImportGraphFromDocument } from '../utils/import-utils.js';
6
+
7
+ /**
8
+ * Langium WorkspaceManager override implementing manifest-centric import loading per PRS-010.
9
+ *
10
+ * Behavior:
11
+ * - Skips pre-loading *.dlang during workspace scan (only entry graph is loaded when manifest exists).
12
+ * - Mode A (with manifest): find nearest model.yaml in folder, load entry (default index.dlang) and its import graph.
13
+ * - Mode B (no manifest): no pre-loading; imports resolved on-demand when a document is opened.
14
+ * - Never performs network fetches; relies on cached dependencies/lock files. Missing cache produces diagnostics upstream.
15
+ */
16
+ export class DomainLangWorkspaceManager extends DefaultWorkspaceManager {
17
+ constructor(services: LangiumSharedCoreServices) {
18
+ super(services);
19
+ }
20
+
21
+ override shouldIncludeEntry(entry: FileSystemNode): boolean {
22
+ // Prevent auto-including .dlang files; we'll load via entry/import graph
23
+ const name = UriUtils.basename(entry.uri);
24
+ if (name.toLowerCase().endsWith('.dlang')) {
25
+ return false;
26
+ }
27
+ return super.shouldIncludeEntry(entry);
28
+ }
29
+
30
+ override async initializeWorkspace(folders: WorkspaceFolder[], cancelToken?: CancellationToken): Promise<void> {
31
+ await super.initializeWorkspace(folders, cancelToken);
32
+ }
33
+
34
+ protected override async loadAdditionalDocuments(folders: WorkspaceFolder[], collector: (document: LangiumDocument) => void): Promise<void> {
35
+ const manifestInfo = await this.findManifestInFolders(folders);
36
+ if (!manifestInfo) {
37
+ return; // Mode B: no manifest
38
+ }
39
+
40
+ const entryUri = URI.file(manifestInfo.entryPath);
41
+ const entryDoc = await this.langiumDocuments.getOrCreateDocument(entryUri);
42
+ collector(entryDoc);
43
+
44
+ const uris = await ensureImportGraphFromDocument(entryDoc, this.langiumDocuments);
45
+ for (const uriString of uris) {
46
+ const uri = URI.parse(uriString);
47
+ const doc = await this.langiumDocuments.getOrCreateDocument(uri);
48
+ collector(doc);
49
+ }
50
+ }
51
+
52
+ private async findManifestInFolders(folders: WorkspaceFolder[]): Promise<{ manifestPath: string; entryPath: string } | undefined> {
53
+ for (const folder of folders) {
54
+ const manifestPath = await this.findNearestManifest(folder.uri);
55
+ if (manifestPath) {
56
+ const entry = await this.readEntryFromManifest(manifestPath) ?? 'index.dlang';
57
+ const entryPath = path.resolve(path.dirname(manifestPath), entry);
58
+ return { manifestPath, entryPath };
59
+ }
60
+ }
61
+ return undefined;
62
+ }
63
+
64
+ private async findNearestManifest(startUri: string): Promise<string | undefined> {
65
+ let current = path.resolve(URI.parse(startUri).fsPath);
66
+ const { root } = path.parse(current);
67
+
68
+ while (true) {
69
+ const candidate = path.join(current, 'model.yaml');
70
+ if (await this.pathExists(candidate)) {
71
+ return candidate;
72
+ }
73
+
74
+ if (current === root) {
75
+ return undefined;
76
+ }
77
+
78
+ const parent = path.dirname(current);
79
+ if (parent === current) {
80
+ return undefined;
81
+ }
82
+ current = parent;
83
+ }
84
+ }
85
+
86
+ private async readEntryFromManifest(manifestPath: string): Promise<string | undefined> {
87
+ try {
88
+ const content = await this.fileSystemProvider.readFile(URI.file(manifestPath));
89
+ const manifest = (YAML.parse(content) ?? {}) as { model?: { entry?: string } };
90
+ return manifest.model?.entry;
91
+ } catch {
92
+ return undefined;
93
+ }
94
+ }
95
+
96
+ private async pathExists(target: string): Promise<boolean> {
97
+ try {
98
+ await this.fileSystemProvider.stat(URI.file(target));
99
+ return true;
100
+ } catch {
101
+ return false;
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,237 @@
1
+ /**
2
+ * DDD Pattern Explanations for Hover Documentation
3
+ *
4
+ * Provides plain-English explanations for DDD integration patterns,
5
+ * relationship types, and decision categories.
6
+ */
7
+
8
+ /**
9
+ * Explanations for DDD integration role patterns (e.g., PL, ACL, SK).
10
+ */
11
+ export const rolePatternExplanations: Record<string, string> = {
12
+ 'PL': `**Published Language (PL)**
13
+
14
+ The upstream context provides a well-documented, stable API/model that downstream contexts consume.
15
+
16
+ \`\`\`domain-lang
17
+ [PL] UpstreamContext -> DownstreamContext
18
+ \`\`\`
19
+
20
+ *Use when:* Multiple consumers need a shared, stable interface.`,
21
+
22
+ 'ACL': `**Anti-Corruption Layer (ACL)**
23
+
24
+ Protects downstream from upstream changes by translating between models.
25
+
26
+ \`\`\`domain-lang
27
+ UpstreamContext -> [ACL] DownstreamContext
28
+ \`\`\`
29
+
30
+ *Use when:* You don't trust upstream stability or want isolation.`,
31
+
32
+ 'SK': `**Shared Kernel (SK)**
33
+
34
+ Both contexts share common domain model code requiring coordination.
35
+
36
+ \`\`\`domain-lang
37
+ [SK] Context1 <-> [SK] Context2 : SharedKernel
38
+ \`\`\`
39
+
40
+ *Use when:* Contexts are tightly coupled and teams can coordinate.`,
41
+
42
+ 'CF': `**Conformist (CF)**
43
+
44
+ Downstream accepts upstream model without translation.
45
+
46
+ \`\`\`domain-lang
47
+ UpstreamContext -> [CF] DownstreamContext
48
+ \`\`\`
49
+
50
+ *Use when:* Upstream model is acceptable and translation isn't worth it.`,
51
+
52
+ 'OHS': `**Open Host Service (OHS)**
53
+
54
+ Upstream defines a protocol/API for easy integration.
55
+
56
+ \`\`\`domain-lang
57
+ [OHS, PL] ApiContext -> ConsumerContext
58
+ \`\`\`
59
+
60
+ *Use when:* Multiple downstream contexts need integration.`,
61
+
62
+ 'P': `**Partnership (P)**
63
+
64
+ Teams coordinate development and align releases.
65
+
66
+ \`\`\`domain-lang
67
+ Context1 <-> Context2 : Partnership
68
+ \`\`\`
69
+
70
+ *Use when:* Mutual success dependency exists.`,
71
+
72
+ 'BBoM': `**Big Ball of Mud (BBoM)**
73
+
74
+ No clear boundaries - tangled models needing refactoring.
75
+
76
+ \`\`\`domain-lang
77
+ [BBoM] LegacySystem -> ModernContext
78
+ \`\`\`
79
+
80
+ *Use when:* Documenting legacy systems.`
81
+ };
82
+
83
+ /**
84
+ * Explanations for relationship types (e.g., Partnership, CustomerSupplier).
85
+ */
86
+ export const relationshipTypeExplanations: Record<string, string> = {
87
+ 'Partnership': '**Partnership**\n\nTwo contexts with mutual success dependency. Teams plan together and coordinate releases.\n\n*Example:* Sales and Order Fulfillment contexts that must evolve in sync.',
88
+
89
+ 'SharedKernel': '**Shared Kernel**\n\nTwo contexts share a subset of code/model. Changes require agreement from both teams.\n\n*Example:* Two closely related contexts sharing common domain entities.',
90
+
91
+ 'CustomerSupplier': '**Customer/Supplier**\n\nDownstream (customer) context depends on upstream (supplier) context. Supplier meets customer\'s needs through negotiation.\n\n*Example:* Payment context (customer) depends on Billing context (supplier).',
92
+
93
+ 'UpstreamDownstream': '**Upstream/Downstream**\n\nUpstream context influences downstream context, but not vice versa. Downstream adapts to upstream changes.\n\n*Example:* Inventory (upstream) provides data to Reporting (downstream).',
94
+
95
+ 'SeparateWays': '**Separate Ways**\n\nNo connection between contexts - they duplicate functionality rather than integrate.\n\n*Use when:* Integration cost exceeds benefit of sharing.'
96
+ };
97
+
98
+ /**
99
+ * Explanations for relationship arrows.
100
+ */
101
+ export const arrowExplanations: Record<string, string> = {
102
+ '<->': 'Bidirectional relationship - both contexts influence each other',
103
+ '->': 'Downstream dependency - right depends on left (left is upstream)',
104
+ '<-': 'Upstream dependency - left depends on right (right is upstream)',
105
+ '><': 'Separate Ways - no integration between contexts',
106
+ 'U/D': 'Upstream/Downstream - shorthand for upstream → downstream flow',
107
+ 'u/d': 'Upstream/Downstream - shorthand for upstream → downstream flow',
108
+ 'C/S': 'Customer/Supplier - shorthand for customer ← supplier relationship',
109
+ 'c/s': 'Customer/Supplier - shorthand for customer ← supplier relationship'
110
+ };
111
+
112
+ /**
113
+ * Explanations for decision categories.
114
+ */
115
+ export const decisionCategoryExplanations: Record<string, string> = {
116
+ 'architectural': '**Architectural Decision**\n\nConcerns system structure, technology choices, or cross-cutting patterns.\n\n*Examples:* Microservices vs monolith, event sourcing, CQRS',
117
+ 'arch': 'Short for "architectural" - concerns system structure and technology choices',
118
+
119
+ 'business': '**Business Decision**\n\nConcerns business rules, policies, or domain logic.\n\n*Examples:* Pricing rules, refund policies, eligibility criteria',
120
+ 'biz': 'Short for "business" - concerns business rules and domain logic',
121
+
122
+ 'technical': '**Technical Decision**\n\nConcerns implementation details, algorithms, or technical constraints.\n\n*Examples:* Caching strategy, data structures, optimization approach',
123
+ 'tech': 'Short for "technical" - concerns implementation details',
124
+
125
+ 'compliance': '**Compliance Decision**\n\nConcerns legal, regulatory, or compliance requirements.\n\n*Examples:* GDPR data retention, SOX audit trails, HIPAA privacy',
126
+
127
+ 'security': '**Security Decision**\n\nConcerns security, authentication, authorization, or data protection.\n\n*Examples:* OAuth vs JWT, encryption at rest, access control',
128
+
129
+ 'operational': '**Operational Decision**\n\nConcerns deployment, monitoring, or operational procedures.\n\n*Examples:* Blue/green deployment, monitoring strategy, backup policy',
130
+ 'ops': 'Short for "operational" - concerns deployment and operations'
131
+ };
132
+
133
+ /**
134
+ * Explanations for common DDD classifications.
135
+ */
136
+ export const classificationExplanations: Record<string, string> = {
137
+ 'Core': '**Core Domain**\n\nThe primary differentiator for your business - this is where you create unique value.\n\n*Invest heavily:* Best team, careful design, deep modeling.\n\n*Example:* Recommendation engine for Netflix, search for Google',
138
+
139
+ 'Supporting': '**Supporting Subdomain**\n\nNecessary for the business but not a differentiator. Custom implementation needed but not the main focus.\n\n*Invest moderately:* Good team, solid implementation.\n\n*Example:* Inventory management, invoicing',
140
+
141
+ 'Generic': '**Generic Subdomain**\n\nSolved problem - could use off-the-shelf solution. No competitive advantage.\n\n*Buy or reuse:* Use existing solutions when possible.\n\n*Example:* User authentication, email sending, payment processing',
142
+
143
+ 'Strategic': '**Strategic** (Wardley Evolution)\n\nNovel, custom-built, competitive advantage. High value, low maturity.\n\n*Similar to Core Domain.*',
144
+
145
+ 'Custom': '**Custom-Built** (Wardley Evolution)\n\nSpecialized solution, some precedent exists. Medium-high value, medium maturity.',
146
+
147
+ 'Product': '**Product/Rental** (Wardley Evolution)\n\nStandardized product with features. Medium value, medium-high maturity.\n\n*Example:* SaaS tools, commercial software',
148
+
149
+ 'Commodity': '**Commodity/Utility** (Wardley Evolution)\n\nUbiquitous, interchangeable, fully standardized. Low value, high maturity.\n\n*Example:* Cloud compute, email services'
150
+ };
151
+
152
+ /**
153
+ * Get explanation for a role pattern.
154
+ */
155
+ export function explainRolePattern(role: string): string | undefined {
156
+ return rolePatternExplanations[role];
157
+ }
158
+
159
+ /**
160
+ * Get explanation for a relationship type.
161
+ */
162
+ export function explainRelationshipType(type: string): string | undefined {
163
+ return relationshipTypeExplanations[type];
164
+ }
165
+
166
+ /**
167
+ * Get explanation for an arrow symbol.
168
+ */
169
+ export function explainArrow(arrow: string): string | undefined {
170
+ return arrowExplanations[arrow];
171
+ }
172
+
173
+ /**
174
+ * Get explanation for a decision category.
175
+ */
176
+ export function explainDecisionCategory(category: string): string | undefined {
177
+ return decisionCategoryExplanations[category];
178
+ }
179
+
180
+ /**
181
+ * Get explanation for a classification.
182
+ */
183
+ export function explainClassification(name: string): string | undefined {
184
+ return classificationExplanations[name];
185
+ }
186
+
187
+ /**
188
+ * Generate relationship explanation from roles and type.
189
+ */
190
+ export function generateRelationshipExplanation(
191
+ leftRoles: string[] | undefined,
192
+ arrow: string | undefined,
193
+ rightRoles: string[] | undefined,
194
+ type: string | undefined
195
+ ): string {
196
+ const parts: string[] = [];
197
+
198
+ // Arrow explanation
199
+ if (arrow) {
200
+ const arrowExp = explainArrow(arrow);
201
+ if (arrowExp) {
202
+ parts.push(`**Arrow:** ${arrowExp}`);
203
+ }
204
+ }
205
+
206
+ // Left roles
207
+ if (leftRoles && leftRoles.length > 0) {
208
+ parts.push('**Left Context Patterns:**');
209
+ leftRoles.forEach(role => {
210
+ const exp = explainRolePattern(role);
211
+ if (exp) {
212
+ parts.push(exp);
213
+ }
214
+ });
215
+ }
216
+
217
+ // Right roles
218
+ if (rightRoles && rightRoles.length > 0) {
219
+ parts.push('**Right Context Patterns:**');
220
+ rightRoles.forEach(role => {
221
+ const exp = explainRolePattern(role);
222
+ if (exp) {
223
+ parts.push(exp);
224
+ }
225
+ });
226
+ }
227
+
228
+ // Relationship type
229
+ if (type) {
230
+ const typeExp = explainRelationshipType(type);
231
+ if (typeExp) {
232
+ parts.push(typeExp);
233
+ }
234
+ }
235
+
236
+ return parts.join('\n\n---\n\n');
237
+ }