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.
- package/README.md +182 -141
- package/dist/errors.d.ts +17 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +26 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/serviceFactory.d.ts +6 -5
- package/dist/serviceFactory.d.ts.map +1 -1
- package/dist/serviceFactory.js +22 -7
- package/dist/serviceFactory.js.map +1 -1
- package/dist/serviceFactoryWrapper.d.ts +2 -0
- package/dist/serviceFactoryWrapper.d.ts.map +1 -0
- package/dist/serviceFactoryWrapper.js +16 -0
- package/dist/serviceFactoryWrapper.js.map +1 -0
- package/dist/serviceKey.d.ts +84 -0
- package/dist/serviceKey.d.ts.map +1 -1
- package/dist/serviceKey.js +83 -2
- package/dist/serviceKey.js.map +1 -1
- package/dist/serviceModule.d.ts +26 -5
- package/dist/serviceModule.d.ts.map +1 -1
- package/dist/serviceModule.js +106 -15
- package/dist/serviceModule.js.map +1 -1
- package/dist/serviceSelector.d.ts +64 -0
- package/dist/serviceSelector.d.ts.map +1 -0
- package/dist/serviceSelector.js +69 -0
- package/dist/serviceSelector.js.map +1 -0
- package/dist/test-service-selector.d.ts +2 -0
- package/dist/test-service-selector.d.ts.map +1 -0
- package/dist/test-service-selector.js +110 -0
- package/dist/test-service-selector.js.map +1 -0
- package/dist/utils.d.ts +33 -6
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +100 -6
- package/dist/utils.js.map +1 -1
- package/package.json +45 -41
- package/src/errors.ts +23 -0
- package/src/index.ts +7 -5
- package/src/serviceFactory.ts +104 -83
- package/src/serviceKey.ts +95 -8
- package/src/serviceModule.ts +223 -123
- package/src/serviceScope.ts +7 -7
- package/src/serviceSelector.ts +68 -0
- 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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
*
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
lines
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
lines.push('');
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
lines.push('
|
|
67
|
-
lines.push(
|
|
68
|
-
lines.push('
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
//
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
factories.forEach((factory) => {
|
|
93
|
-
const serviceName = factory.provides.name;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
+
}
|