composed-di 0.0.3 → 0.0.5-alpha
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 +65 -26
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -8
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +12 -281
- package/dist/main.js.map +1 -0
- package/dist/serviceFactory.d.ts +28 -20
- package/dist/serviceFactory.d.ts.map +1 -1
- package/dist/serviceFactory.js +40 -30
- package/dist/serviceFactory.js.map +1 -1
- package/dist/serviceKey.d.ts +1 -1
- package/dist/serviceKey.d.ts.map +1 -1
- package/dist/serviceKey.js +1 -1
- package/dist/serviceKey.js.map +1 -1
- package/dist/serviceModule.d.ts +7 -8
- package/dist/serviceModule.d.ts.map +1 -1
- package/dist/serviceModule.js +1 -1
- package/dist/serviceModule.js.map +1 -1
- package/dist/utils.d.ts +26 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +107 -0
- package/dist/utils.js.map +1 -0
- package/package.json +1 -1
- package/src/ServiceFactory.ts +83 -0
- package/src/{serviceModule.ts → ServiceModule.ts} +102 -101
- package/src/index.ts +4 -4
- package/src/utils.ts +141 -0
- package/src/serviceFactory.ts +0 -69
- package/src/serviceProvider.ts +0 -5
- /package/src/{serviceKey.ts → ServiceKey.ts} +0 -0
package/src/utils.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
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 module - The ServiceModule to convert to DOT notation
|
|
31
|
+
* @param options - Optional configuration for the graph appearance
|
|
32
|
+
* @returns A string containing the DOT notation graph
|
|
33
|
+
*/
|
|
34
|
+
export function createDotGraph(
|
|
35
|
+
module: ServiceModule,
|
|
36
|
+
{ direction, title, highlightLeaves, highlightRoots }: DotGraphOptions = {
|
|
37
|
+
direction: 'BT',
|
|
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 dependency to dependent (what provides -> what needs it)
|
|
126
|
+
lines.push(` ${depNodeId} -> ${serviceNodeId};`);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Close the digraph
|
|
132
|
+
lines.push('}');
|
|
133
|
+
|
|
134
|
+
return lines.join('\n');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function printDotGraph(module: ServiceModule) {
|
|
138
|
+
console.log(createDotGraph(module));
|
|
139
|
+
console.log('\n\nCopy the DOT output above and paste it into:');
|
|
140
|
+
console.log('https://dreampuf.github.io/GraphvizOnline/');
|
|
141
|
+
}
|
package/src/serviceFactory.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { ServiceKey } from './serviceKey';
|
|
2
|
-
|
|
3
|
-
// Helper types to extract the type from ServiceKey
|
|
4
|
-
type ServiceType<T> = T extends ServiceKey<infer U> ? U : never;
|
|
5
|
-
|
|
6
|
-
// Helper types to convert an array of ServiceKey to tuple of their types
|
|
7
|
-
type DependencyTypes<T extends ServiceKey<unknown>[]> = {
|
|
8
|
-
[K in keyof T]: ServiceType<T[K]>;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export interface ServiceFactory<T, D extends ServiceKey<unknown>[] = []> {
|
|
12
|
-
provides: ServiceKey<T>;
|
|
13
|
-
dependsOn: D;
|
|
14
|
-
|
|
15
|
-
initialize(...dependencies: DependencyTypes<D>): Promise<T>;
|
|
16
|
-
|
|
17
|
-
dispose(instance: T): void;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function singletonFactory<T, D extends ServiceKey<unknown>[] = []>({
|
|
21
|
-
provides,
|
|
22
|
-
dependsOn = [] as unknown as D,
|
|
23
|
-
initialize,
|
|
24
|
-
dispose = () => {},
|
|
25
|
-
}: {
|
|
26
|
-
provides: ServiceKey<T>;
|
|
27
|
-
dependsOn?: D;
|
|
28
|
-
initialize: (...dependencies: DependencyTypes<D>) => Promise<T>;
|
|
29
|
-
dispose?: (instance: T) => void;
|
|
30
|
-
}): ServiceFactory<T, D> {
|
|
31
|
-
let instance: T | undefined;
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
provides,
|
|
35
|
-
dependsOn,
|
|
36
|
-
async initialize(...dependencies: DependencyTypes<D>): Promise<T> {
|
|
37
|
-
if (instance) {
|
|
38
|
-
return instance;
|
|
39
|
-
}
|
|
40
|
-
instance = await initialize(...dependencies);
|
|
41
|
-
return instance;
|
|
42
|
-
},
|
|
43
|
-
dispose(serviceInstance: T): void {
|
|
44
|
-
if (instance === serviceInstance) {
|
|
45
|
-
dispose(serviceInstance);
|
|
46
|
-
instance = undefined;
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function oneShotFactory<T, D extends ServiceKey<unknown>[] = []>({
|
|
53
|
-
provides,
|
|
54
|
-
dependsOn,
|
|
55
|
-
initialize,
|
|
56
|
-
dispose = () => {},
|
|
57
|
-
}: {
|
|
58
|
-
provides: ServiceKey<T>;
|
|
59
|
-
dependsOn: D;
|
|
60
|
-
initialize: (...dependencies: DependencyTypes<D>) => Promise<T>;
|
|
61
|
-
dispose?: (instance: T) => void;
|
|
62
|
-
}): ServiceFactory<T, D> {
|
|
63
|
-
return {
|
|
64
|
-
provides,
|
|
65
|
-
dependsOn,
|
|
66
|
-
initialize,
|
|
67
|
-
dispose,
|
|
68
|
-
};
|
|
69
|
-
}
|
package/src/serviceProvider.ts
DELETED
|
File without changes
|