@kridaydave/code-mapper 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.
- package/AGENTS.md +174 -0
- package/LICENSE.md +21 -0
- package/README.md +113 -0
- package/dist/graph/Graph.test.js +173 -0
- package/dist/graph/Graph.test.js.map +1 -0
- package/dist/graph/GraphAnalyzer.js +435 -0
- package/dist/graph/GraphAnalyzer.js.map +1 -0
- package/dist/graph/GraphBuilder.js +225 -0
- package/dist/graph/GraphBuilder.js.map +1 -0
- package/dist/graph/types.js +2 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/cache.js +72 -0
- package/dist/mcp/cache.js.map +1 -0
- package/dist/mcp/resources.js +119 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/tools.js +444 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/tools.test.js +81 -0
- package/dist/mcp/tools.test.js.map +1 -0
- package/dist/parser/ComplexityAnalyzer.js +208 -0
- package/dist/parser/ComplexityAnalyzer.js.map +1 -0
- package/dist/parser/FileAnalyzer.js +191 -0
- package/dist/parser/FileAnalyzer.js.map +1 -0
- package/dist/parser/ProjectParser.js +134 -0
- package/dist/parser/ProjectParser.js.map +1 -0
- package/dist/parser/ProjectParser.test.js +77 -0
- package/dist/parser/ProjectParser.test.js.map +1 -0
- package/dist/parser/types.js +2 -0
- package/dist/parser/types.js.map +1 -0
- package/docs/PHASE2_PLAN.md +435 -0
- package/fixtures/test-project/calculator.ts +28 -0
- package/fixtures/test-project/index.ts +2 -0
- package/fixtures/test-project/math.ts +11 -0
- package/package.json +35 -0
- package/src/graph/Graph.test.ts +222 -0
- package/src/graph/GraphAnalyzer.ts +502 -0
- package/src/graph/GraphBuilder.ts +258 -0
- package/src/graph/types.ts +42 -0
- package/src/index.ts +38 -0
- package/src/mcp/cache.ts +89 -0
- package/src/mcp/resources.ts +137 -0
- package/src/mcp/tools.test.ts +104 -0
- package/src/mcp/tools.ts +529 -0
- package/src/parser/ComplexityAnalyzer.ts +275 -0
- package/src/parser/FileAnalyzer.ts +215 -0
- package/src/parser/ProjectParser.test.ts +96 -0
- package/src/parser/ProjectParser.ts +172 -0
- package/src/parser/types.ts +77 -0
- package/src/types/graphology-pagerank.d.ts +20 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +15 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Codebase Cartographer Agent Guidelines
|
|
2
|
+
|
|
3
|
+
## Build, Lint, and Test Commands
|
|
4
|
+
|
|
5
|
+
### Build Commands
|
|
6
|
+
- `npm run build` - Compiles TypeScript to JavaScript using tsc
|
|
7
|
+
- Output directory: ./dist (configured in tsconfig.json)
|
|
8
|
+
- Entry point: dist/index.js
|
|
9
|
+
|
|
10
|
+
### Development Commands
|
|
11
|
+
- `npm run dev` - Runs the MCP server directly with tsx for development
|
|
12
|
+
- Uses tsx for instant TypeScript execution without compilation
|
|
13
|
+
- Primary development workflow
|
|
14
|
+
|
|
15
|
+
### Production Commands
|
|
16
|
+
- `npm start` - Runs the compiled JavaScript from dist/index.js
|
|
17
|
+
- Used after running npm run build
|
|
18
|
+
|
|
19
|
+
### Testing Guidelines
|
|
20
|
+
No existing test framework is configured in this repository. For adding tests:
|
|
21
|
+
|
|
22
|
+
1. **Recommended Setup**:
|
|
23
|
+
```bash
|
|
24
|
+
npm install --save-dev vitest @vitest/coverage-v8
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
2. **Add to package.json**:
|
|
28
|
+
```json
|
|
29
|
+
"scripts": {
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"test:watch": "vitest",
|
|
32
|
+
"test:cover": "vitest run --coverage"
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
3. **Test File Convention**:
|
|
37
|
+
- Place tests in __tests__ directory or alongside source files with .test.ts suffix
|
|
38
|
+
- Example: src/mcp/tools.test.ts
|
|
39
|
+
|
|
40
|
+
4. **Running Specific Tests**:
|
|
41
|
+
- Single test file: `npx vitest src/mcp/tools.test.ts`
|
|
42
|
+
- Test with pattern: `npx vitest run -t "scan_codebase"`
|
|
43
|
+
|
|
44
|
+
### Type Checking
|
|
45
|
+
- `npx tsc --noEmit` - Performs type checking without emitting files
|
|
46
|
+
- Already enabled via "strict": true in tsconfig.json
|
|
47
|
+
- Run as part of CI/CD pipeline
|
|
48
|
+
|
|
49
|
+
## Code Style Guidelines
|
|
50
|
+
|
|
51
|
+
### Import Order
|
|
52
|
+
1. Node.js built-in modules (`node:path`, `node:fs`)
|
|
53
|
+
2. External libraries (`@modelcontextprotocol/server`, `zod`, `ts-morph`)
|
|
54
|
+
3. Internal project imports (relative paths)
|
|
55
|
+
4. Sort alphabetically within each group
|
|
56
|
+
5. Prefer named imports over default imports when practical
|
|
57
|
+
|
|
58
|
+
Example:
|
|
59
|
+
```typescript
|
|
60
|
+
import { resolve } from "node:path";
|
|
61
|
+
import * as fs from "node:fs";
|
|
62
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
63
|
+
import { z } from "zod";
|
|
64
|
+
import { ProjectParser } from "../parser/ProjectParser.js";
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Formatting
|
|
68
|
+
- Indentation: 2 spaces
|
|
69
|
+
- Line width: Maximum 100 characters (soft limit)
|
|
70
|
+
- Semicolons: Required
|
|
71
|
+
- Quotes: Single quotes for strings
|
|
72
|
+
- Trailing commas: Multiline objects and arrays
|
|
73
|
+
- Function spacing: Empty line between function declarations
|
|
74
|
+
- Brace style: Opening brace on same line, closing brace on new line
|
|
75
|
+
|
|
76
|
+
### Types and Interfaces
|
|
77
|
+
- Prefer interfaces for object shapes that may be extended
|
|
78
|
+
- Use type aliases for unions, primitives, and mapped types
|
|
79
|
+
- Enable strict null checks (`strict`: true in tsconfig)
|
|
80
|
+
- Explicit return types for exported functions
|
|
81
|
+
- Use `unknown` instead of `any` when type is truly unknown
|
|
82
|
+
- Specify generic constraints when possible
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
```typescript
|
|
86
|
+
interface FileInfo {
|
|
87
|
+
relativePath: string;
|
|
88
|
+
functions: FunctionInfo[];
|
|
89
|
+
classes: ClassInfo[];
|
|
90
|
+
imports: ImportInfo[];
|
|
91
|
+
exports: ExportInfo[];
|
|
92
|
+
totalLines: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
type GraphCallback = (node: GraphNode) => boolean | void;
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Naming Conventions
|
|
99
|
+
- Variables and functions: camelCase
|
|
100
|
+
- Classes and interfaces: PascalCase
|
|
101
|
+
- Constants: UPPER_SNAKE_CASE
|
|
102
|
+
- File names: kebab-case (.ts files)
|
|
103
|
+
- Acronyms: Treat as normal words (e.g., "getNodeID" not "getNodeId")
|
|
104
|
+
- Private properties: No underscore prefix (use TypeScript privacy modifiers)
|
|
105
|
+
|
|
106
|
+
Example:
|
|
107
|
+
```typescript
|
|
108
|
+
class ProjectParser {
|
|
109
|
+
private cache: Map<string, ParseResult> = new Map();
|
|
110
|
+
|
|
111
|
+
async parse(directory: string): Promise<ParseResult> {
|
|
112
|
+
// implementation
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private findFiles(directory: string): string[] {
|
|
116
|
+
// implementation
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Error Handling
|
|
122
|
+
- Use try/catch for asynchronous operations
|
|
123
|
+
- Provide meaningful error messages with context
|
|
124
|
+
- Don't catch errors unless you can handle or enhance them
|
|
125
|
+
- For MCP tools, errors are automatically caught and returned as error content
|
|
126
|
+
- Validate inputs early using Zod schemas (already implemented)
|
|
127
|
+
- Process exits with non-zero code for unrecoverable errors (see index.ts)
|
|
128
|
+
|
|
129
|
+
### Comments and Documentation
|
|
130
|
+
- JSDoc comments for all exported functions and classes
|
|
131
|
+
- Explain non-obvious logic with inline comments
|
|
132
|
+
- Keep comments up-to-date when modifying code
|
|
133
|
+
- Use TODO: and FIXME: comments for tracking work
|
|
134
|
+
- Document complex type manipulations
|
|
135
|
+
|
|
136
|
+
Example:
|
|
137
|
+
```typescript
|
|
138
|
+
/**
|
|
139
|
+
* Scans a directory and returns a summary of all files, functions, classes, and their relationships.
|
|
140
|
+
* Use this first before any other analysis.
|
|
141
|
+
*/
|
|
142
|
+
server.registerTool("scan_codebase", {
|
|
143
|
+
// ...
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Project-Specific Patterns
|
|
148
|
+
- MCP tool registration follows consistent pattern in tools.ts
|
|
149
|
+
- Shared cache pattern used in mcp/cache.ts for analyzer instances
|
|
150
|
+
- Error handling in main() function with process.exit(1) for fatal errors
|
|
151
|
+
- Shebang line in index.ts for direct execution
|
|
152
|
+
- Graph algorithms separated from MCP interface layer
|
|
153
|
+
- Parsing and analysis layers clearly separated
|
|
154
|
+
|
|
155
|
+
### Dependency Management
|
|
156
|
+
- Keep dependencies up-to-date with `npm update`
|
|
157
|
+
- Audit for vulnerabilities with `npm audit`
|
|
158
|
+
- Peer dependencies not used in this project
|
|
159
|
+
- Dev dependencies limited to TypeScript tooling
|
|
160
|
+
|
|
161
|
+
## MCP Protocol Implementation
|
|
162
|
+
All MCP tools follow this pattern:
|
|
163
|
+
1. Define tool name, description, and input/output schemas using Zod
|
|
164
|
+
2. Implement handler function with proper async/await
|
|
165
|
+
3. Return structured content with text and structuredContent fields
|
|
166
|
+
4. Handle edge cases (empty results, not found, etc.)
|
|
167
|
+
5. Use analyzer cache to avoid reprocessing same directories
|
|
168
|
+
|
|
169
|
+
## File Organization
|
|
170
|
+
- src/index.ts - MCP server entry point
|
|
171
|
+
- src/mcp/ - MCP-specific code (tools, resources, caching)
|
|
172
|
+
- src/parser/ - TS-Morph based code analysis
|
|
173
|
+
- src/graph/ - Graph theory algorithms and data structures
|
|
174
|
+
- Separation of concerns between parsing, analysis, and MCP interface
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CodeGraph
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
21
|
+
DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# CodeGraph
|
|
2
|
+
|
|
3
|
+
An MCP server that uses AST parsing to map TypeScript/JavaScript codebase structure and expose codebase intelligence for AI assistants.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **AST-based analysis** - Uses `ts-morph` (TypeScript compiler API) to parse code without running it
|
|
8
|
+
- **Dependency graphs** - Builds graph representations of how files, functions, and classes relate
|
|
9
|
+
- **Impact ranking** - Identifies the most central/critical files using graph centrality metrics
|
|
10
|
+
- **Call chain tracing** - Finds dependency paths between any two symbols
|
|
11
|
+
- **Mermaid diagrams** - Generates visual dependency diagrams
|
|
12
|
+
|
|
13
|
+
## MCP Tools
|
|
14
|
+
|
|
15
|
+
| Tool | Description |
|
|
16
|
+
|------|-------------|
|
|
17
|
+
| `scan_codebase` | Scan a directory and return a summary of all files, functions, classes, and relationships |
|
|
18
|
+
| `find_function` | Search for a function or class by name, returns location, signature, callers, and callees |
|
|
19
|
+
| `analyze_dependencies` | Returns the full dependency graph or a subgraph for a specific file (JSON or Mermaid) |
|
|
20
|
+
| `rank_impact` | Ranks files by centrality (in-degree, out-degree, betweenness) to identify critical modules |
|
|
21
|
+
| `trace_call_chain` | Traces the call chain / dependency path from one function or file to another |
|
|
22
|
+
|
|
23
|
+
## MCP Resources
|
|
24
|
+
|
|
25
|
+
| Resource | Description |
|
|
26
|
+
|----------|-------------|
|
|
27
|
+
| `codebase://summary` | Cached summary of the most recently scanned codebase |
|
|
28
|
+
| `codebase://graph/{format}` | Dependency graph in `json` or `mermaid` format |
|
|
29
|
+
|
|
30
|
+
## Setup
|
|
31
|
+
|
|
32
|
+
### Install
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install
|
|
36
|
+
npm run build
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Use with Claude Desktop (or any MCP client)
|
|
40
|
+
|
|
41
|
+
Add this to your MCP client configuration:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcpServers": {
|
|
46
|
+
"CodeGraph": {
|
|
47
|
+
"command": "npx",
|
|
48
|
+
"args": ["tsx", "/absolute/path/to/CodeGraph/src/index.ts"]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Or after building:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"CodeGraph": {
|
|
60
|
+
"command": "node",
|
|
61
|
+
"args": ["/absolute/path/to/CodeGraph/dist/index.js"]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Usage
|
|
68
|
+
|
|
69
|
+
Once connected, AI assistants can:
|
|
70
|
+
|
|
71
|
+
1. **Scan your codebase**: "Scan my codebase at ./src"
|
|
72
|
+
2. **Find symbols**: "Where is the authenticate function defined and who calls it?"
|
|
73
|
+
3. **Analyze dependencies**: "Show me the dependency graph as mermaid"
|
|
74
|
+
4. **Rank impact**: "What's the most central file in my project?"
|
|
75
|
+
5. **Trace paths**: "Trace the call chain from handleRequest to saveToDatabase"
|
|
76
|
+
|
|
77
|
+
## Architecture
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
src/
|
|
81
|
+
├── index.ts # MCP server entry point (stdio transport)
|
|
82
|
+
├── parser/
|
|
83
|
+
│ ├── types.ts # FileInfo, FunctionInfo, ClassInfo, etc.
|
|
84
|
+
│ ├── FileAnalyzer.ts # ts-morph single-file analysis
|
|
85
|
+
│ └── ProjectParser.ts # Directory scanning with caching
|
|
86
|
+
├── graph/
|
|
87
|
+
│ ├── types.ts # GraphNode, GraphEdge, RankedFile, etc.
|
|
88
|
+
│ ├── GraphBuilder.ts # Converts ParseResult to graphology Graph
|
|
89
|
+
│ └── GraphAnalyzer.ts # Centrality, path finding, cycle detection
|
|
90
|
+
└── mcp/
|
|
91
|
+
├── cache.ts # Shared analyzer cache
|
|
92
|
+
├── tools.ts # 5 MCP tool definitions
|
|
93
|
+
└── resources.ts # MCP resource definitions
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Tech Stack
|
|
97
|
+
|
|
98
|
+
- **ts-morph** - TypeScript AST parsing (wraps the TypeScript compiler API)
|
|
99
|
+
- **graphology** - Graph data structure for dependency mapping
|
|
100
|
+
- **graphology-metrics** - Centrality algorithms (betweenness, degree, etc.)
|
|
101
|
+
- **graphology-shortest-path** - Bidirectional shortest path finding
|
|
102
|
+
- **@modelcontextprotocol/server** - MCP server SDK with stdio transport
|
|
103
|
+
- **zod** - Schema validation for tool inputs
|
|
104
|
+
|
|
105
|
+
## Ignored Directories
|
|
106
|
+
|
|
107
|
+
By default, these directories are excluded from scanning:
|
|
108
|
+
- `node_modules`, `dist`, `build`, `.git`, `coverage`
|
|
109
|
+
- `.next`, `.nuxt`, `.svelte-kit`, `__tests__`, `.cache`
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
MIT
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
+
import { ProjectParser } from "../parser/ProjectParser.js";
|
|
3
|
+
import { GraphBuilder } from "../graph/GraphBuilder.js";
|
|
4
|
+
import { GraphAnalyzer } from "../graph/GraphAnalyzer.js";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
describe("GraphBuilder", () => {
|
|
7
|
+
let parser;
|
|
8
|
+
let builder;
|
|
9
|
+
let parseResult;
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
parser = new ProjectParser();
|
|
12
|
+
builder = new GraphBuilder();
|
|
13
|
+
const testDir = path.resolve("./fixtures/test-project");
|
|
14
|
+
parseResult = await parser.parse(testDir);
|
|
15
|
+
});
|
|
16
|
+
describe("build", () => {
|
|
17
|
+
it("should build a graph from parse result", () => {
|
|
18
|
+
const { graph, nodes, edges } = builder.build(parseResult);
|
|
19
|
+
expect(graph.order).toBeGreaterThan(0);
|
|
20
|
+
expect(nodes.length).toBeGreaterThan(0);
|
|
21
|
+
expect(edges.length).toBeGreaterThan(0);
|
|
22
|
+
});
|
|
23
|
+
it("should create file nodes", () => {
|
|
24
|
+
const { nodes } = builder.build(parseResult);
|
|
25
|
+
const fileNodes = nodes.filter(n => n.kind === "file");
|
|
26
|
+
expect(fileNodes.length).toBe(3);
|
|
27
|
+
});
|
|
28
|
+
it("should create function nodes", () => {
|
|
29
|
+
const { nodes } = builder.build(parseResult);
|
|
30
|
+
const fnNodes = nodes.filter(n => n.kind === "function");
|
|
31
|
+
expect(fnNodes.length).toBe(3);
|
|
32
|
+
});
|
|
33
|
+
it("should create class nodes", () => {
|
|
34
|
+
const { nodes } = builder.build(parseResult);
|
|
35
|
+
const classNodes = nodes.filter(n => n.kind === "class");
|
|
36
|
+
expect(classNodes.length).toBe(1);
|
|
37
|
+
});
|
|
38
|
+
it("should create import edges between files", () => {
|
|
39
|
+
const { edges } = builder.build(parseResult);
|
|
40
|
+
const importEdges = edges.filter(e => e.kind === "imports");
|
|
41
|
+
expect(importEdges.length).toBeGreaterThan(0);
|
|
42
|
+
});
|
|
43
|
+
it("should create containment edges", () => {
|
|
44
|
+
const { edges } = builder.build(parseResult);
|
|
45
|
+
const containsEdges = edges.filter(e => e.kind === "contains");
|
|
46
|
+
expect(containsEdges.length).toBeGreaterThan(0);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe("GraphAnalyzer", () => {
|
|
51
|
+
let parser;
|
|
52
|
+
let builder;
|
|
53
|
+
let analyzer;
|
|
54
|
+
let parseResult;
|
|
55
|
+
beforeEach(async () => {
|
|
56
|
+
parser = new ProjectParser();
|
|
57
|
+
builder = new GraphBuilder();
|
|
58
|
+
const testDir = path.resolve("./fixtures/test-project");
|
|
59
|
+
parseResult = await parser.parse(testDir);
|
|
60
|
+
const { graph, nodes, edges } = builder.build(parseResult);
|
|
61
|
+
analyzer = new GraphAnalyzer(graph, parseResult, nodes, edges);
|
|
62
|
+
});
|
|
63
|
+
describe("rankImpact", () => {
|
|
64
|
+
it("should rank files by in-degree", () => {
|
|
65
|
+
const ranked = analyzer.rankImpact("inDegree");
|
|
66
|
+
expect(ranked.length).toBeGreaterThan(0);
|
|
67
|
+
expect(ranked[0]).toHaveProperty("relativePath");
|
|
68
|
+
expect(ranked[0]).toHaveProperty("score");
|
|
69
|
+
});
|
|
70
|
+
it("should rank files by out-degree", () => {
|
|
71
|
+
const ranked = analyzer.rankImpact("outDegree");
|
|
72
|
+
expect(ranked.length).toBeGreaterThan(0);
|
|
73
|
+
});
|
|
74
|
+
it("should rank files by betweenness", () => {
|
|
75
|
+
const ranked = analyzer.rankImpact("betweenness");
|
|
76
|
+
expect(ranked.length).toBeGreaterThan(0);
|
|
77
|
+
});
|
|
78
|
+
it("should include file metrics in ranking", () => {
|
|
79
|
+
const ranked = analyzer.rankImpact("inDegree");
|
|
80
|
+
expect(ranked[0]).toHaveProperty("functionCount");
|
|
81
|
+
expect(ranked[0]).toHaveProperty("classCount");
|
|
82
|
+
expect(ranked[0]).toHaveProperty("importCount");
|
|
83
|
+
expect(ranked[0]).toHaveProperty("exportCount");
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe("findFunction", () => {
|
|
87
|
+
it("should find functions by name", () => {
|
|
88
|
+
const matches = analyzer.findFunction("add", "function");
|
|
89
|
+
expect(matches.length).toBeGreaterThan(0);
|
|
90
|
+
expect(matches[0].name).toBe("add");
|
|
91
|
+
});
|
|
92
|
+
it("should find classes by name", () => {
|
|
93
|
+
const matches = analyzer.findFunction("Calculator", "class");
|
|
94
|
+
expect(matches.length).toBe(1);
|
|
95
|
+
expect(matches[0].name).toBe("Calculator");
|
|
96
|
+
});
|
|
97
|
+
it("should find both functions and classes when type is any", () => {
|
|
98
|
+
const matches = analyzer.findFunction("Calculator", "any");
|
|
99
|
+
expect(matches.length).toBe(1);
|
|
100
|
+
});
|
|
101
|
+
it("should return empty for non-existent symbol", () => {
|
|
102
|
+
const matches = analyzer.findFunction("NonExistentSymbol", "any");
|
|
103
|
+
expect(matches).toEqual([]);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe("getCallers and getCallees", () => {
|
|
107
|
+
it("should get callers for a node", () => {
|
|
108
|
+
const nodes = analyzer.getNodes();
|
|
109
|
+
const fileNode = nodes.find(n => n.kind === "file" && n.label.includes("calculator"));
|
|
110
|
+
if (fileNode) {
|
|
111
|
+
const callers = analyzer.getCallers(fileNode.id);
|
|
112
|
+
expect(callers).toBeDefined();
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
it("should get callees for a node", () => {
|
|
116
|
+
const nodes = analyzer.getNodes();
|
|
117
|
+
const fileNode = nodes.find(n => n.kind === "file" && n.label.includes("calculator"));
|
|
118
|
+
if (fileNode) {
|
|
119
|
+
const callees = analyzer.getCallees(fileNode.id);
|
|
120
|
+
expect(callees).toBeDefined();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe("traceCallChain", () => {
|
|
125
|
+
it("should find paths between nodes", () => {
|
|
126
|
+
const result = analyzer.traceCallChain("add", "Calculator");
|
|
127
|
+
expect(result).toHaveProperty("found");
|
|
128
|
+
expect(result).toHaveProperty("paths");
|
|
129
|
+
});
|
|
130
|
+
it("should return empty for non-existent nodes", () => {
|
|
131
|
+
const result = analyzer.traceCallChain("NonExistent", "AlsoNotHere");
|
|
132
|
+
expect(result.found).toBe(false);
|
|
133
|
+
expect(result.paths).toEqual([]);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe("toMermaid", () => {
|
|
137
|
+
it("should generate mermaid diagram", () => {
|
|
138
|
+
const mermaid = analyzer.toMermaid();
|
|
139
|
+
expect(mermaid).toContain("graph TD");
|
|
140
|
+
expect(mermaid).toContain("-->");
|
|
141
|
+
});
|
|
142
|
+
it("should filter by target file", () => {
|
|
143
|
+
const mermaid = analyzer.toMermaid("calculator");
|
|
144
|
+
expect(mermaid).toContain("graph TD");
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
describe("detectCycles", () => {
|
|
148
|
+
it("should detect cycles in the graph", () => {
|
|
149
|
+
const cycles = analyzer.detectCycles();
|
|
150
|
+
expect(cycles).toBeDefined();
|
|
151
|
+
expect(Array.isArray(cycles)).toBe(true);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
describe("getGraph, getNodes, getEdges, getParseResult", () => {
|
|
155
|
+
it("should return the graph", () => {
|
|
156
|
+
const graph = analyzer.getGraph();
|
|
157
|
+
expect(graph).toBeDefined();
|
|
158
|
+
});
|
|
159
|
+
it("should return nodes", () => {
|
|
160
|
+
const nodes = analyzer.getNodes();
|
|
161
|
+
expect(nodes.length).toBeGreaterThan(0);
|
|
162
|
+
});
|
|
163
|
+
it("should return edges", () => {
|
|
164
|
+
const edges = analyzer.getEdges();
|
|
165
|
+
expect(edges.length).toBeGreaterThan(0);
|
|
166
|
+
});
|
|
167
|
+
it("should return parse result", () => {
|
|
168
|
+
const result = analyzer.getParseResult();
|
|
169
|
+
expect(result.totalFiles).toBe(3);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
//# sourceMappingURL=Graph.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Graph.test.js","sourceRoot":"","sources":["../../src/graph/Graph.test.ts"],"names":[],"mappings":"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"}
|