@ebowwa/dependency-graph 1.0.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.
@@ -0,0 +1,145 @@
1
+ /**
2
+ * @ebowwa/dependency-graph - Output Formatters
3
+ *
4
+ * Format dependency graphs for various output formats
5
+ */
6
+ /**
7
+ * Format the graph for output
8
+ */
9
+ export function formatGraph(graph, format) {
10
+ switch (format) {
11
+ case "mermaid":
12
+ return formatAsMermaid(graph);
13
+ case "dot":
14
+ return formatAsDot(graph);
15
+ case "tree":
16
+ return formatAsTree(graph);
17
+ case "json":
18
+ default:
19
+ return formatAsJson(graph);
20
+ }
21
+ }
22
+ /**
23
+ * Format as JSON
24
+ */
25
+ export function formatAsJson(graph) {
26
+ return JSON.stringify({
27
+ nodes: Array.from(graph.nodes.values()),
28
+ edges: graph.edges,
29
+ }, null, 2);
30
+ }
31
+ /**
32
+ * Format as Mermaid diagram
33
+ */
34
+ export function formatAsMermaid(graph) {
35
+ const lines = ["graph TD"];
36
+ // Add nodes
37
+ for (const [name, node] of graph.nodes) {
38
+ const label = node.type === "workspace" ? `📦 ${name}` : `📚 ${name}`;
39
+ lines.push(` ${sanitizeId(name)}["${label}"]`);
40
+ }
41
+ // Add edges
42
+ for (const edge of graph.edges) {
43
+ const from = sanitizeId(edge.from);
44
+ const to = sanitizeId(edge.to);
45
+ const label = edge.type === "workspace"
46
+ ? "workspace"
47
+ : edge.type === "import"
48
+ ? "imports"
49
+ : "external";
50
+ lines.push(` ${from} -->|${label}| ${to}`);
51
+ }
52
+ // Add styles
53
+ lines.push(" classDef workspace fill:#e1f5fe");
54
+ lines.push(" classDef external fill:#f5f5f5");
55
+ lines.push(" classDef import fill:#fff3e0");
56
+ for (const [name, node] of graph.nodes) {
57
+ const id = sanitizeId(name);
58
+ if (node.type === "workspace") {
59
+ lines.push(` class ${id} workspace`);
60
+ }
61
+ else if (node.type === "external") {
62
+ lines.push(` class ${id} external`);
63
+ }
64
+ }
65
+ return lines.join("\n");
66
+ }
67
+ /**
68
+ * Format as Graphviz DOT
69
+ */
70
+ export function formatAsDot(graph) {
71
+ const lines = ["digraph dependencies {"];
72
+ lines.push(" rankdir=LR;");
73
+ lines.push(" node [shape=box];");
74
+ // Add nodes
75
+ for (const [name, node] of graph.nodes) {
76
+ const color = node.type === "workspace" ? "lightblue" : "lightgray";
77
+ lines.push(` "${name}" [fillcolor=${color}, style=filled];`);
78
+ }
79
+ // Add edges
80
+ for (const edge of graph.edges) {
81
+ const style = edge.type === "workspace" ? "solid" : "dashed";
82
+ lines.push(` "${edge.from}" -> "${edge.to}" [style=${style}, label="${edge.type}"];`);
83
+ }
84
+ lines.push("}");
85
+ return lines.join("\n");
86
+ }
87
+ /**
88
+ * Format as ASCII tree
89
+ */
90
+ export function formatAsTree(graph) {
91
+ const lines = [];
92
+ const seen = new Set();
93
+ // Find root nodes (no incoming edges from other workspace packages)
94
+ const workspaceNodes = Array.from(graph.nodes.values()).filter((n) => n.type === "workspace");
95
+ const incomingEdges = new Map();
96
+ for (const node of workspaceNodes) {
97
+ incomingEdges.set(node.name, 0);
98
+ }
99
+ for (const edge of graph.edges) {
100
+ if (graph.nodes.get(edge.to)?.type === "workspace") {
101
+ incomingEdges.set(edge.to, (incomingEdges.get(edge.to) || 0) + 1);
102
+ }
103
+ }
104
+ // Start from roots
105
+ for (const [name, node] of graph.nodes) {
106
+ if (node.type === "workspace" && (incomingEdges.get(name) || 0) === 0) {
107
+ lines.push(`📦 ${name}`);
108
+ printTree(graph, name, "", seen, lines);
109
+ }
110
+ }
111
+ // Add any disconnected nodes
112
+ for (const [name, node] of graph.nodes) {
113
+ if (!seen.has(name) && node.type === "workspace") {
114
+ lines.push(`📦 ${name} (disconnected)`);
115
+ }
116
+ }
117
+ return lines.join("\n");
118
+ }
119
+ function printTree(graph, nodeName, prefix, seen, lines) {
120
+ seen.add(nodeName);
121
+ // Find outgoing edges to other workspace packages
122
+ const outgoing = graph.edges.filter((e) => e.from === nodeName && graph.nodes.get(e.to)?.type === "workspace");
123
+ for (let i = 0; i < outgoing.length; i++) {
124
+ const edge = outgoing[i];
125
+ const isLast = i === outgoing.length - 1;
126
+ const connector = isLast ? "└──" : "├──";
127
+ const childPrefix = prefix + (isLast ? " " : "│ ");
128
+ lines.push(`${prefix}${connector} 📦 ${edge.to} [${edge.type}]`);
129
+ if (!seen.has(edge.to)) {
130
+ printTree(graph, edge.to, childPrefix, seen, lines);
131
+ }
132
+ }
133
+ // Show external dependencies count
134
+ const externals = graph.edges.filter((e) => e.from === nodeName && graph.nodes.get(e.to)?.type === "external");
135
+ if (externals.length > 0) {
136
+ lines.push(`${prefix}└── 📚 ${externals.length} external dependencies`);
137
+ }
138
+ }
139
+ /**
140
+ * Sanitize ID for Mermaid/DOT formats
141
+ */
142
+ function sanitizeId(name) {
143
+ return name.replace(/[^a-zA-Z0-9]/g, "_");
144
+ }
145
+ //# sourceMappingURL=formatters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.js","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @ebowwa/dependency-graph
3
+ *
4
+ * Core dependency graph analysis and visualization for monorepos
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { DependencyGraphBuilder, formatGraph, analyzeImpact, findCircularDependencies } from '@ebowwa/dependency-graph';
9
+ *
10
+ * const builder = new DependencyGraphBuilder('/path/to/monorepo');
11
+ * const graph = await builder.build({ analyzeImports: true });
12
+ *
13
+ * // Format as Mermaid diagram
14
+ * const mermaid = formatGraph(graph, 'mermaid');
15
+ *
16
+ * // Find circular dependencies
17
+ * const cycles = findCircularDependencies(graph);
18
+ *
19
+ * // Analyze impact of changing a package
20
+ * const impact = analyzeImpact(graph, '@ebowwa/terminal');
21
+ * ```
22
+ */
23
+ export type { DependencyNode, DependencyEdge, DependencyGraph, ImportInfo, BuildOptions, ImpactResult, OutputFormat, PackageInfo, } from "./types.js";
24
+ export { DependencyGraphBuilder } from "./builder.js";
25
+ export { findCircularDependencies, analyzeImpact, findUnusedPackages, getPackageInfo, getWorkspacePackages, getExternalDependencies, } from "./analysis.js";
26
+ export { formatGraph, formatAsJson, formatAsMermaid, formatAsDot, formatAsTree, } from "./formatters.js";
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,YAAY,EACV,cAAc,EACd,cAAc,EACd,eAAe,EACf,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,GACZ,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAGtD,OAAO,EACL,wBAAwB,EACxB,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,eAAe,EACf,WAAW,EACX,YAAY,GACb,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @ebowwa/dependency-graph
3
+ *
4
+ * Core dependency graph analysis and visualization for monorepos
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { DependencyGraphBuilder, formatGraph, analyzeImpact, findCircularDependencies } from '@ebowwa/dependency-graph';
9
+ *
10
+ * const builder = new DependencyGraphBuilder('/path/to/monorepo');
11
+ * const graph = await builder.build({ analyzeImports: true });
12
+ *
13
+ * // Format as Mermaid diagram
14
+ * const mermaid = formatGraph(graph, 'mermaid');
15
+ *
16
+ * // Find circular dependencies
17
+ * const cycles = findCircularDependencies(graph);
18
+ *
19
+ * // Analyze impact of changing a package
20
+ * const impact = analyzeImpact(graph, '@ebowwa/terminal');
21
+ * ```
22
+ */
23
+ // Builder
24
+ export { DependencyGraphBuilder } from "./builder.js";
25
+ // Analysis
26
+ export { findCircularDependencies, analyzeImpact, findUnusedPackages, getPackageInfo, getWorkspacePackages, getExternalDependencies, } from "./analysis.js";
27
+ // Formatters
28
+ export { formatGraph, formatAsJson, formatAsMermaid, formatAsDot, formatAsTree, } from "./formatters.js";
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAcH,UAAU;AACV,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEtD,WAAW;AACX,OAAO,EACL,wBAAwB,EACxB,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAEvB,aAAa;AACb,OAAO,EACL,WAAW,EACX,YAAY,EACZ,eAAe,EACf,WAAW,EACX,YAAY,GACb,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @ebowwa/dependency-graph - Core Types
3
+ *
4
+ * Type definitions for dependency graph analysis
5
+ */
6
+ export interface DependencyNode {
7
+ name: string;
8
+ path: string;
9
+ type: "package" | "workspace" | "external";
10
+ version?: string;
11
+ }
12
+ export interface DependencyEdge {
13
+ from: string;
14
+ to: string;
15
+ type: "workspace" | "external" | "import";
16
+ importPath?: string;
17
+ }
18
+ export interface DependencyGraph {
19
+ nodes: Map<string, DependencyNode>;
20
+ edges: DependencyEdge[];
21
+ reverseEdges: Map<string, Set<string>>;
22
+ }
23
+ export interface ImportInfo {
24
+ from: string;
25
+ imports: string[];
26
+ file: string;
27
+ }
28
+ export interface BuildOptions {
29
+ includeDevDependencies?: boolean;
30
+ analyzeImports?: boolean;
31
+ excludePatterns?: string[];
32
+ }
33
+ export interface ImpactResult {
34
+ direct: string[];
35
+ transitive: string[];
36
+ all: string[];
37
+ }
38
+ export type OutputFormat = "json" | "mermaid" | "dot" | "tree";
39
+ export interface PackageInfo {
40
+ name: string;
41
+ type: "package" | "workspace" | "external";
42
+ path: string;
43
+ version?: string;
44
+ dependencies: Array<{
45
+ name: string;
46
+ type: "workspace" | "external" | "import";
47
+ version?: string;
48
+ }>;
49
+ dependents: string[];
50
+ }
51
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACnC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;AAE/D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,KAAK,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;QAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB"}
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @ebowwa/dependency-graph - Core Types
3
+ *
4
+ * Type definitions for dependency graph analysis
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@ebowwa/dependency-graph",
3
+ "version": "1.0.0",
4
+ "description": "Core dependency graph analysis and visualization for monorepos",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src"
21
+ ],
22
+ "keywords": [
23
+ "dependency",
24
+ "graph",
25
+ "monorepo",
26
+ "visualization",
27
+ "impact-analysis"
28
+ ],
29
+ "author": "ebowwa",
30
+ "license": "MIT",
31
+ "devDependencies": {
32
+ "@types/node": "^22.10.2",
33
+ "typescript": "^5.7.2"
34
+ },
35
+ "engines": {
36
+ "node": ">=20.0.0"
37
+ }
38
+ }
@@ -0,0 +1,188 @@
1
+ /**
2
+ * @ebowwa/dependency-graph - Analysis Functions
3
+ *
4
+ * Circular dependency detection, impact analysis, unused code detection
5
+ */
6
+
7
+ import type { DependencyGraph, ImpactResult, PackageInfo } from "./types.js";
8
+
9
+ /**
10
+ * Find circular dependencies using DFS
11
+ */
12
+ export function findCircularDependencies(
13
+ graph: DependencyGraph,
14
+ maxDepth: number = 10
15
+ ): string[][] {
16
+ const cycles: string[][] = [];
17
+ const visited = new Set<string>();
18
+ const recursionStack = new Set<string>();
19
+
20
+ function dfs(node: string, path: string[]): void {
21
+ if (path.length > maxDepth) return;
22
+
23
+ visited.add(node);
24
+ recursionStack.add(node);
25
+ path.push(node);
26
+
27
+ // Check all outgoing edges
28
+ for (const edge of graph.edges) {
29
+ if (edge.from === node) {
30
+ if (recursionStack.has(edge.to)) {
31
+ // Found a cycle
32
+ const cycleStart = path.indexOf(edge.to);
33
+ if (cycleStart >= 0) {
34
+ cycles.push([...path.slice(cycleStart), edge.to]);
35
+ }
36
+ } else if (!visited.has(edge.to)) {
37
+ dfs(edge.to, [...path]);
38
+ }
39
+ }
40
+ }
41
+
42
+ recursionStack.delete(node);
43
+ }
44
+
45
+ // Start DFS from each workspace node
46
+ for (const [name, node] of graph.nodes) {
47
+ if (node.type === "workspace" && !visited.has(name)) {
48
+ dfs(name, []);
49
+ }
50
+ }
51
+
52
+ return cycles;
53
+ }
54
+
55
+ /**
56
+ * Analyze the impact of changing a package
57
+ */
58
+ export function analyzeImpact(
59
+ graph: DependencyGraph,
60
+ packageName: string,
61
+ includeTransitive: boolean = true
62
+ ): ImpactResult {
63
+ const direct: string[] = [];
64
+ const transitive: string[] = [];
65
+ const visited = new Set<string>();
66
+
67
+ // Get direct dependents
68
+ const directDependents = graph.reverseEdges.get(packageName);
69
+ if (directDependents) {
70
+ for (const dep of directDependents) {
71
+ direct.push(dep);
72
+ visited.add(dep);
73
+ }
74
+ }
75
+
76
+ // Get transitive dependents
77
+ if (includeTransitive) {
78
+ for (const dep of direct) {
79
+ collectTransitive(graph, dep, visited, transitive);
80
+ }
81
+ }
82
+
83
+ return {
84
+ direct,
85
+ transitive,
86
+ all: Array.from(visited),
87
+ };
88
+ }
89
+
90
+ function collectTransitive(
91
+ graph: DependencyGraph,
92
+ packageName: string,
93
+ visited: Set<string>,
94
+ result: string[]
95
+ ): void {
96
+ const dependents = graph.reverseEdges.get(packageName);
97
+ if (!dependents) return;
98
+
99
+ for (const dep of dependents) {
100
+ if (!visited.has(dep)) {
101
+ visited.add(dep);
102
+ result.push(dep);
103
+ collectTransitive(graph, dep, visited, result);
104
+ }
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Find potentially unused packages (no dependents)
110
+ */
111
+ export function findUnusedPackages(
112
+ graph: DependencyGraph,
113
+ includeExternal: boolean = false
114
+ ): string[] {
115
+ const unused: string[] = [];
116
+
117
+ for (const [name, node] of graph.nodes) {
118
+ if (node.type === "workspace" || includeExternal) {
119
+ const dependents = graph.reverseEdges.get(name);
120
+ if (!dependents || dependents.size === 0) {
121
+ unused.push(name);
122
+ }
123
+ }
124
+ }
125
+
126
+ return unused;
127
+ }
128
+
129
+ /**
130
+ * Get detailed information about a specific package
131
+ */
132
+ export function getPackageInfo(
133
+ graph: DependencyGraph,
134
+ packageName: string
135
+ ): PackageInfo | null {
136
+ const node = graph.nodes.get(packageName);
137
+ if (!node) return null;
138
+
139
+ // Get dependencies
140
+ const dependencies = graph.edges
141
+ .filter((e) => e.from === packageName)
142
+ .map((edge) => {
143
+ const depNode = graph.nodes.get(edge.to);
144
+ return {
145
+ name: edge.to,
146
+ type: edge.type,
147
+ version: depNode?.version,
148
+ };
149
+ });
150
+
151
+ // Get dependents
152
+ const dependents = Array.from(graph.reverseEdges.get(packageName) || []);
153
+
154
+ return {
155
+ name: packageName,
156
+ type: node.type,
157
+ path: node.path || "N/A",
158
+ version: node.version,
159
+ dependencies,
160
+ dependents,
161
+ };
162
+ }
163
+
164
+ /**
165
+ * Get all workspace packages
166
+ */
167
+ export function getWorkspacePackages(graph: DependencyGraph): string[] {
168
+ const packages: string[] = [];
169
+ for (const [name, node] of graph.nodes) {
170
+ if (node.type === "workspace") {
171
+ packages.push(name);
172
+ }
173
+ }
174
+ return packages;
175
+ }
176
+
177
+ /**
178
+ * Get all external dependencies
179
+ */
180
+ export function getExternalDependencies(graph: DependencyGraph): string[] {
181
+ const deps: string[] = [];
182
+ for (const [name, node] of graph.nodes) {
183
+ if (node.type === "external") {
184
+ deps.push(name);
185
+ }
186
+ }
187
+ return deps;
188
+ }