composed-di 0.2.9-ts4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +182 -141
  2. package/dist/errors.d.ts +17 -0
  3. package/dist/errors.d.ts.map +1 -0
  4. package/dist/errors.js +26 -0
  5. package/dist/errors.js.map +1 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/serviceFactory.d.ts +6 -5
  11. package/dist/serviceFactory.d.ts.map +1 -1
  12. package/dist/serviceFactory.js +22 -7
  13. package/dist/serviceFactory.js.map +1 -1
  14. package/dist/serviceFactoryWrapper.d.ts +2 -0
  15. package/dist/serviceFactoryWrapper.d.ts.map +1 -0
  16. package/dist/serviceFactoryWrapper.js +16 -0
  17. package/dist/serviceFactoryWrapper.js.map +1 -0
  18. package/dist/serviceKey.d.ts +84 -0
  19. package/dist/serviceKey.d.ts.map +1 -1
  20. package/dist/serviceKey.js +83 -2
  21. package/dist/serviceKey.js.map +1 -1
  22. package/dist/serviceModule.d.ts +26 -5
  23. package/dist/serviceModule.d.ts.map +1 -1
  24. package/dist/serviceModule.js +106 -15
  25. package/dist/serviceModule.js.map +1 -1
  26. package/dist/serviceSelector.d.ts +64 -0
  27. package/dist/serviceSelector.d.ts.map +1 -0
  28. package/dist/serviceSelector.js +69 -0
  29. package/dist/serviceSelector.js.map +1 -0
  30. package/dist/test-service-selector.d.ts +2 -0
  31. package/dist/test-service-selector.d.ts.map +1 -0
  32. package/dist/test-service-selector.js +110 -0
  33. package/dist/test-service-selector.js.map +1 -0
  34. package/dist/utils.d.ts +33 -6
  35. package/dist/utils.d.ts.map +1 -1
  36. package/dist/utils.js +100 -6
  37. package/dist/utils.js.map +1 -1
  38. package/package.json +45 -41
  39. package/src/errors.ts +23 -0
  40. package/src/index.ts +7 -5
  41. package/src/serviceFactory.ts +104 -83
  42. package/src/serviceKey.ts +95 -8
  43. package/src/serviceModule.ts +223 -123
  44. package/src/serviceScope.ts +7 -7
  45. package/src/serviceSelector.ts +68 -0
  46. package/src/utils.ts +277 -152
package/src/utils.ts CHANGED
@@ -1,152 +1,277 @@
1
- import { ServiceModule } from './serviceModule';
2
- import { ServiceKey } from './serviceKey';
3
-
4
- export interface DotGraphOptions {
5
- /** Graph direction: 'TB' (top-bottom), 'LR' (left-right), 'BT' (bottom-top), 'RL' (right-left) */
6
- direction?: 'TB' | 'LR' | 'BT' | 'RL';
7
- /** Title for the graph */
8
- title?: string;
9
- /** Show nodes with no dependencies in a different color */
10
- highlightLeaves?: boolean;
11
- /** Show nodes with no dependents in a different color */
12
- highlightRoots?: boolean;
13
- }
14
-
15
- /**
16
- * Escapes special characters in strings for DOT notation
17
- */
18
- function escapeDotString(str: string): string {
19
- return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
20
- }
21
-
22
- /**
23
- * Generates a DOT notation graph from a ServiceModule.
24
- * The output can be visualized using Graphviz tools or online viewers like:
25
- * - https://dreampuf.github.io/GraphvizOnline/
26
- * - https://edotor.net/
27
- *
28
- * Arrows point from dependencies to dependents (from what is needed to what needs it).
29
- *
30
- * @param {ServiceModule} module - The ServiceModule to convert to DOT notation
31
- * @param {DotGraphOptions} options - Optional configuration for the graph appearance
32
- * @returns {string} A string containing the DOT notation graph
33
- */
34
- export function createDotGraph(
35
- module: ServiceModule,
36
- { direction, title, highlightLeaves, highlightRoots }: DotGraphOptions = {
37
- direction: 'TB',
38
- title: 'Service Dependency Graph',
39
- highlightLeaves: true,
40
- highlightRoots: true,
41
- },
42
- ): string {
43
- const factories = module.factories;
44
- const lines: string[] = [];
45
-
46
- // Start the digraph
47
- lines.push('digraph ServiceDependencies {');
48
- lines.push(` label="${title}";`);
49
- lines.push(' labelloc="t";');
50
- lines.push(' fontsize=16;');
51
- lines.push(` rankdir=${direction};`);
52
- lines.push('');
53
-
54
- // Default node styling
55
- lines.push(' node [');
56
- lines.push(' shape=box,');
57
- lines.push(' style="rounded,filled",');
58
- lines.push(' fillcolor="#e1f5ff",');
59
- lines.push(' color="#0288d1",');
60
- lines.push(' fontname="Arial",');
61
- lines.push(' fontsize=12');
62
- lines.push(' ];');
63
- lines.push('');
64
-
65
- // Default edge styling
66
- lines.push(' edge [');
67
- lines.push(' color="#666666",');
68
- lines.push(' arrowsize=0.8');
69
- lines.push(' ];');
70
- lines.push('');
71
-
72
- // Build dependency maps to identify leaves and roots
73
- const hasDependencies = new Set<string>();
74
- const hasDependents = new Set<string>();
75
-
76
- factories.forEach((factory) => {
77
- const serviceName = factory.provides.name;
78
-
79
- if (factory.dependsOn.length > 0) {
80
- hasDependencies.add(serviceName);
81
- }
82
-
83
- factory.dependsOn.forEach((dependency: ServiceKey<unknown>) => {
84
- hasDependents.add(dependency.name);
85
- });
86
- });
87
-
88
- // Define nodes with special styling for leaves and roots
89
- const nodeIds = new Map<string, string>();
90
- let nodeCounter = 0;
91
-
92
- factories.forEach((factory) => {
93
- const serviceName = factory.provides.name;
94
- const nodeId = `node${nodeCounter++}`;
95
- nodeIds.set(serviceName, nodeId);
96
-
97
- const isLeaf = !hasDependencies.has(serviceName);
98
- const isRoot = !hasDependents.has(serviceName);
99
-
100
- let nodeStyle = '';
101
-
102
- if (highlightLeaves && isLeaf) {
103
- nodeStyle = ' [fillcolor="#c8e6c9", color="#388e3c"]';
104
- } else if (highlightRoots && isRoot) {
105
- nodeStyle = ' [fillcolor="#ffccbc", color="#d84315"]';
106
- }
107
-
108
- lines.push(
109
- ` ${nodeId} [label="${escapeDotString(serviceName)}"]${nodeStyle};`,
110
- );
111
- });
112
-
113
- lines.push('');
114
-
115
- // Define edges (dependencies)
116
- factories.forEach((factory) => {
117
- const serviceName = factory.provides.name;
118
- const serviceNodeId = nodeIds.get(serviceName)!;
119
-
120
- factory.dependsOn.forEach((dependency: ServiceKey<unknown>) => {
121
- const depName = dependency.name;
122
- const depNodeId = nodeIds.get(depName);
123
-
124
- if (depNodeId) {
125
- // Arrow points from dependent to dependency (what needs it -> what provides it)
126
- lines.push(` ${serviceNodeId} -> ${depNodeId};`);
127
- }
128
- });
129
- });
130
-
131
- // Close the digraph
132
- lines.push('}');
133
-
134
- return lines.join('\n');
135
- }
136
-
137
- /**
138
- * Prints a DOT representation of a service module graph to the console.
139
- * The output can be used to visualize the graph using online graph visualization tools.
140
- *
141
- * @param {ServiceModule} module - The service module representing the graph to be converted into DOT format.
142
- * @param {DotGraphOptions} [options] - Optional configurations to customize the output of the DOT graph.
143
- * @return {void} - This function does not return a value.
144
- */
145
- export function printDotGraph(
146
- module: ServiceModule,
147
- options?: DotGraphOptions,
148
- ): void {
149
- console.log(createDotGraph(module, options));
150
- console.log('\n\nCopy the DOT output above and paste it into:');
151
- console.log('https://dreampuf.github.io/GraphvizOnline/');
152
- }
1
+ import { ServiceModule } from './serviceModule';
2
+ import { ServiceKey } from './serviceKey';
3
+
4
+ export interface DotGraphOptions {
5
+ /** Graph direction: 'TB' (top-bottom), 'LR' (left-right), 'BT' (bottom-top), 'RL' (right-left) */
6
+ direction?: 'TB' | 'LR' | 'BT' | 'RL';
7
+ /** Title for the graph */
8
+ title?: string;
9
+ /** Show nodes with no dependencies in a different color */
10
+ highlightLeaves?: boolean;
11
+ /** Show nodes with no dependents in a different color */
12
+ highlightRoots?: boolean;
13
+ }
14
+
15
+ export interface MermaidGraphOptions {
16
+ /** Graph direction: 'TB' (top-bottom), 'LR' (left-right), 'BT' (bottom-top), 'RL' (right-left) */
17
+ direction?: 'TB' | 'LR' | 'BT' | 'RL';
18
+ /** Show nodes with no dependencies in a different color */
19
+ highlightLeaves?: boolean;
20
+ /** Show nodes with no dependents in a different color */
21
+ highlightRoots?: boolean;
22
+ }
23
+
24
+ /**
25
+ * Escapes special characters in strings for DOT notation
26
+ */
27
+ function escapeDotString(str: string): string {
28
+ return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
29
+ }
30
+
31
+ /**
32
+ * Escapes special characters in strings for Mermaid notation
33
+ */
34
+ function escapeMermaidString(str: string): string {
35
+ return str.replace(/"/g, '#quot;');
36
+ }
37
+
38
+ /**
39
+ * Generates a DOT notation graph from a ServiceModule.
40
+ * The output can be visualized using Graphviz tools or online viewers like:
41
+ * - https://dreampuf.github.io/GraphvizOnline/
42
+ * - https://edotor.net/
43
+ *
44
+ * Arrows point from dependencies to dependents (from what is needed to what needs it).
45
+ *
46
+ * @param module - The ServiceModule to convert to DOT notation
47
+ * @param options - Optional configuration for the graph appearance
48
+ * @returns A string containing the DOT notation graph
49
+ */
50
+ export function createDotGraph(
51
+ module: ServiceModule,
52
+ { direction, title, highlightLeaves, highlightRoots }: DotGraphOptions = {
53
+ direction: 'TB',
54
+ title: 'Service Dependency Graph',
55
+ highlightLeaves: true,
56
+ highlightRoots: true,
57
+ },
58
+ ): string {
59
+ const factories = module.factories;
60
+ const lines: string[] = [];
61
+
62
+ // Start the digraph
63
+ lines.push('digraph ServiceDependencies {');
64
+ lines.push(` label="${title}";`);
65
+ lines.push(' labelloc="t";');
66
+ lines.push(' fontsize=16;');
67
+ lines.push(` rankdir=${direction};`);
68
+ lines.push('');
69
+
70
+ // Default node styling
71
+ lines.push(' node [');
72
+ lines.push(' shape=box,');
73
+ lines.push(' style="rounded,filled",');
74
+ lines.push(' fillcolor="#e1f5ff",');
75
+ lines.push(' color="#0288d1",');
76
+ lines.push(' fontname="Arial",');
77
+ lines.push(' fontsize=12');
78
+ lines.push(' ];');
79
+ lines.push('');
80
+
81
+ // Default edge styling
82
+ lines.push(' edge [');
83
+ lines.push(' color="#666666",');
84
+ lines.push(' arrowsize=0.8');
85
+ lines.push(' ];');
86
+ lines.push('');
87
+
88
+ // Build dependency maps to identify leaves and roots
89
+ const hasDependencies = new Set<string>();
90
+ const hasDependents = new Set<string>();
91
+
92
+ factories.forEach((factory) => {
93
+ const serviceName = factory.provides.name;
94
+
95
+ if (factory.dependsOn.length > 0) {
96
+ hasDependencies.add(serviceName);
97
+ }
98
+
99
+ factory.dependsOn.forEach((dependency: ServiceKey<unknown>) => {
100
+ hasDependents.add(dependency.name);
101
+ });
102
+ });
103
+
104
+ // Define nodes with special styling for leaves and roots
105
+ const nodeIds = new Map<string, string>();
106
+ let nodeCounter = 0;
107
+
108
+ factories.forEach((factory) => {
109
+ const serviceName = factory.provides.name;
110
+ const nodeId = `node${nodeCounter++}`;
111
+ nodeIds.set(serviceName, nodeId);
112
+
113
+ const isLeaf = !hasDependencies.has(serviceName);
114
+ const isRoot = !hasDependents.has(serviceName);
115
+
116
+ let nodeStyle = '';
117
+
118
+ if (highlightLeaves && isLeaf) {
119
+ nodeStyle = ' [fillcolor="#c8e6c9", color="#388e3c"]';
120
+ } else if (highlightRoots && isRoot) {
121
+ nodeStyle = ' [fillcolor="#ffccbc", color="#d84315"]';
122
+ }
123
+
124
+ lines.push(
125
+ ` ${nodeId} [label="${escapeDotString(serviceName)}"]${nodeStyle};`,
126
+ );
127
+ });
128
+
129
+ lines.push('');
130
+
131
+ // Define edges (dependencies)
132
+ factories.forEach((factory) => {
133
+ const serviceName = factory.provides.name;
134
+ const serviceNodeId = nodeIds.get(serviceName)!;
135
+
136
+ factory.dependsOn.forEach((dependency: ServiceKey<unknown>) => {
137
+ const depName = dependency.name;
138
+ const depNodeId = nodeIds.get(depName);
139
+
140
+ if (depNodeId) {
141
+ // Arrow points from dependent to dependency (what needs it -> what provides it)
142
+ lines.push(` ${serviceNodeId} -> ${depNodeId};`);
143
+ }
144
+ });
145
+ });
146
+
147
+ // Close the digraph
148
+ lines.push('}');
149
+
150
+ return lines.join('\n');
151
+ }
152
+
153
+ /**
154
+ * Prints a DOT representation of a service module graph to the console.
155
+ * The output can be used to visualize the graph using online graph visualization tools.
156
+ *
157
+ * @param module - The service module representing the graph to be converted into DOT format.
158
+ * @param options - Optional configurations to customize the output of the DOT graph.
159
+ */
160
+ export function printDotGraph(
161
+ module: ServiceModule,
162
+ options?: DotGraphOptions,
163
+ ): void {
164
+ console.log(createDotGraph(module, options));
165
+ console.log('\n\nCopy the DOT output above and paste it into:');
166
+ console.log('https://dreampuf.github.io/GraphvizOnline/');
167
+ }
168
+
169
+ /**
170
+ * Generates a Mermaid flowchart from a ServiceModule.
171
+ * The output can be visualized using Mermaid-compatible tools or online viewers like:
172
+ * - https://mermaid.live/
173
+ *
174
+ * Arrows point from dependents to dependencies (what needs it -> what provides it).
175
+ *
176
+ * @param module - The ServiceModule to convert to Mermaid notation
177
+ * @param options - Optional configuration for the graph appearance
178
+ * @returns A string containing the Mermaid flowchart
179
+ */
180
+ export function createMermaidGraph(
181
+ module: ServiceModule,
182
+ { direction, highlightLeaves, highlightRoots }: MermaidGraphOptions = {
183
+ direction: 'TB',
184
+ highlightLeaves: true,
185
+ highlightRoots: true,
186
+ },
187
+ ): string {
188
+ const factories = module.factories;
189
+ const lines: string[] = [];
190
+
191
+ // Start the flowchart
192
+ lines.push(`flowchart ${direction}`);
193
+
194
+ // Build dependency maps to identify leaves and roots
195
+ const hasDependencies = new Set<string>();
196
+ const hasDependents = new Set<string>();
197
+
198
+ factories.forEach((factory) => {
199
+ const serviceName = factory.provides.name;
200
+
201
+ if (factory.dependsOn.length > 0) {
202
+ hasDependencies.add(serviceName);
203
+ }
204
+
205
+ factory.dependsOn.forEach((dependency) => {
206
+ hasDependents.add(dependency.name);
207
+ });
208
+ });
209
+
210
+ // Define nodes with special styling for leaves and roots
211
+ const nodeIds = new Map<string, string>();
212
+ let nodeCounter = 0;
213
+
214
+ factories.forEach((factory) => {
215
+ const serviceName = factory.provides.name;
216
+ const nodeId = `node${nodeCounter++}`;
217
+ nodeIds.set(serviceName, nodeId);
218
+
219
+ lines.push(` ${nodeId}["${escapeMermaidString(serviceName)}"]`);
220
+ });
221
+
222
+ lines.push('');
223
+
224
+ // Define edges (dependencies)
225
+ factories.forEach((factory) => {
226
+ const serviceName = factory.provides.name;
227
+ const serviceNodeId = nodeIds.get(serviceName)!;
228
+
229
+ factory.dependsOn.forEach((dependency) => {
230
+ const depName = dependency.name;
231
+ const depNodeId = nodeIds.get(depName);
232
+
233
+ if (depNodeId) {
234
+ // Arrow points from dependent to dependency (what needs it -> what provides it)
235
+ lines.push(` ${serviceNodeId} --> ${depNodeId}`);
236
+ }
237
+ });
238
+ });
239
+
240
+ lines.push('');
241
+
242
+ // Apply styling
243
+ factories.forEach((factory) => {
244
+ const serviceName = factory.provides.name;
245
+ const serviceNodeId = nodeIds.get(serviceName)!;
246
+
247
+ const isLeaf = !hasDependencies.has(serviceName);
248
+ const isRoot = !hasDependents.has(serviceName);
249
+
250
+ if (highlightLeaves && isLeaf) {
251
+ lines.push(` style ${serviceNodeId} fill:#c8e6c9,stroke:#388e3c`);
252
+ } else if (highlightRoots && isRoot) {
253
+ lines.push(` style ${serviceNodeId} fill:#ffccbc,stroke:#d84315`);
254
+ } else {
255
+ // Default style
256
+ lines.push(` style ${serviceNodeId} fill:#e1f5ff,stroke:#0288d1`);
257
+ }
258
+ });
259
+
260
+ return lines.join('\n');
261
+ }
262
+
263
+ /**
264
+ * Prints a Mermaid representation of a service module graph to the console.
265
+ * The output can be used to visualize the graph using online Mermaid tools.
266
+ *
267
+ * @param module - The service module representing the graph to be converted into Mermaid format.
268
+ * @param options - Optional configurations to customize the output of the Mermaid graph.
269
+ */
270
+ export function printMermaidGraph(
271
+ module: ServiceModule,
272
+ options?: MermaidGraphOptions,
273
+ ): void {
274
+ console.log(createMermaidGraph(module, options));
275
+ console.log('\n\nCopy the Mermaid output above and paste it into:');
276
+ console.log('https://mermaid.live/');
277
+ }