@shvmgyl15/tsgraph 0.1.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 +64 -0
- package/README.md +128 -0
- package/TODOS.md +61 -0
- package/dist/analysis/analysis.test.d.ts +2 -0
- package/dist/analysis/analysis.test.d.ts.map +1 -0
- package/dist/analysis/analysis.test.js +359 -0
- package/dist/analysis/analysis.test.js.map +1 -0
- package/dist/analysis/complexity.d.ts +8 -0
- package/dist/analysis/complexity.d.ts.map +1 -0
- package/dist/analysis/complexity.js +88 -0
- package/dist/analysis/complexity.js.map +1 -0
- package/dist/analysis/coupling.d.ts +17 -0
- package/dist/analysis/coupling.d.ts.map +1 -0
- package/dist/analysis/coupling.js +71 -0
- package/dist/analysis/coupling.js.map +1 -0
- package/dist/analysis/hotspot.d.ts +10 -0
- package/dist/analysis/hotspot.d.ts.map +1 -0
- package/dist/analysis/hotspot.js +33 -0
- package/dist/analysis/hotspot.js.map +1 -0
- package/dist/analysis/index.d.ts +9 -0
- package/dist/analysis/index.d.ts.map +1 -0
- package/dist/analysis/index.js +5 -0
- package/dist/analysis/index.js.map +1 -0
- package/dist/boundaries/index.d.ts +25 -0
- package/dist/boundaries/index.d.ts.map +1 -0
- package/dist/boundaries/index.js +103 -0
- package/dist/boundaries/index.js.map +1 -0
- package/dist/boundaries/index.test.d.ts +2 -0
- package/dist/boundaries/index.test.d.ts.map +1 -0
- package/dist/boundaries/index.test.js +293 -0
- package/dist/boundaries/index.test.js.map +1 -0
- package/dist/changes/index.d.ts +28 -0
- package/dist/changes/index.d.ts.map +1 -0
- package/dist/changes/index.js +48 -0
- package/dist/changes/index.js.map +1 -0
- package/dist/changes/index.test.d.ts +2 -0
- package/dist/changes/index.test.d.ts.map +1 -0
- package/dist/changes/index.test.js +104 -0
- package/dist/changes/index.test.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +659 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/git/index.d.ts +16 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +73 -0
- package/dist/git/index.js.map +1 -0
- package/dist/git/index.test.d.ts +2 -0
- package/dist/git/index.test.d.ts.map +1 -0
- package/dist/git/index.test.js +78 -0
- package/dist/git/index.test.js.map +1 -0
- package/dist/graph/types.d.ts +156 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +166 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/graph/types.test.d.ts +2 -0
- package/dist/graph/types.test.d.ts.map +1 -0
- package/dist/graph/types.test.js +326 -0
- package/dist/graph/types.test.js.map +1 -0
- package/dist/mcp/mcp.test.d.ts +2 -0
- package/dist/mcp/mcp.test.d.ts.map +1 -0
- package/dist/mcp/mcp.test.js +151 -0
- package/dist/mcp/mcp.test.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +209 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/nextjs/index.d.ts +8 -0
- package/dist/nextjs/index.d.ts.map +1 -0
- package/dist/nextjs/index.js +16 -0
- package/dist/nextjs/index.js.map +1 -0
- package/dist/nextjs/nextjs.test.d.ts +2 -0
- package/dist/nextjs/nextjs.test.d.ts.map +1 -0
- package/dist/nextjs/nextjs.test.js +190 -0
- package/dist/nextjs/nextjs.test.js.map +1 -0
- package/dist/nextjs/pages.d.ts +4 -0
- package/dist/nextjs/pages.d.ts.map +1 -0
- package/dist/nextjs/pages.js +36 -0
- package/dist/nextjs/pages.js.map +1 -0
- package/dist/nextjs/react.d.ts +3 -0
- package/dist/nextjs/react.d.ts.map +1 -0
- package/dist/nextjs/react.js +86 -0
- package/dist/nextjs/react.js.map +1 -0
- package/dist/nextjs/router.d.ts +4 -0
- package/dist/nextjs/router.d.ts.map +1 -0
- package/dist/nextjs/router.js +86 -0
- package/dist/nextjs/router.js.map +1 -0
- package/dist/nextjs/routes.d.ts +4 -0
- package/dist/nextjs/routes.d.ts.map +1 -0
- package/dist/nextjs/routes.js +58 -0
- package/dist/nextjs/routes.js.map +1 -0
- package/dist/opencode/index.d.ts +7 -0
- package/dist/opencode/index.d.ts.map +1 -0
- package/dist/opencode/index.js +71 -0
- package/dist/opencode/index.js.map +1 -0
- package/dist/opencode/index.test.d.ts +2 -0
- package/dist/opencode/index.test.d.ts.map +1 -0
- package/dist/opencode/index.test.js +71 -0
- package/dist/opencode/index.test.js.map +1 -0
- package/dist/parser/index.d.ts +4 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +282 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/parser.test.d.ts +2 -0
- package/dist/parser/parser.test.d.ts.map +1 -0
- package/dist/parser/parser.test.js +225 -0
- package/dist/parser/parser.test.js.map +1 -0
- package/dist/plan/index.d.ts +32 -0
- package/dist/plan/index.d.ts.map +1 -0
- package/dist/plan/index.js +107 -0
- package/dist/plan/index.js.map +1 -0
- package/dist/plan/index.test.d.ts +2 -0
- package/dist/plan/index.test.d.ts.map +1 -0
- package/dist/plan/index.test.js +143 -0
- package/dist/plan/index.test.js.map +1 -0
- package/dist/report/index.d.ts +9 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +108 -0
- package/dist/report/index.js.map +1 -0
- package/dist/scanner/index.d.ts +13 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +78 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/scanner.test.d.ts +2 -0
- package/dist/scanner/scanner.test.d.ts.map +1 -0
- package/dist/scanner/scanner.test.js +113 -0
- package/dist/scanner/scanner.test.js.map +1 -0
- package/dist/search/index.d.ts +32 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +97 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/search.test.d.ts +2 -0
- package/dist/search/search.test.d.ts.map +1 -0
- package/dist/search/search.test.js +446 -0
- package/dist/search/search.test.js.map +1 -0
- package/dist/traversal/index.d.ts +5 -0
- package/dist/traversal/index.d.ts.map +1 -0
- package/dist/traversal/index.js +3 -0
- package/dist/traversal/index.js.map +1 -0
- package/dist/traversal/traversal.d.ts +31 -0
- package/dist/traversal/traversal.d.ts.map +1 -0
- package/dist/traversal/traversal.js +130 -0
- package/dist/traversal/traversal.js.map +1 -0
- package/dist/traversal/traversal.test.d.ts +2 -0
- package/dist/traversal/traversal.test.d.ts.map +1 -0
- package/dist/traversal/traversal.test.js +224 -0
- package/dist/traversal/traversal.test.js.map +1 -0
- package/opencode.json +24 -0
- package/package.json +29 -0
- package/src/analysis/analysis.test.ts +405 -0
- package/src/analysis/complexity.ts +107 -0
- package/src/analysis/coupling.ts +106 -0
- package/src/analysis/hotspot.ts +52 -0
- package/src/analysis/index.ts +17 -0
- package/src/boundaries/index.test.ts +335 -0
- package/src/boundaries/index.ts +137 -0
- package/src/changes/index.test.ts +114 -0
- package/src/changes/index.ts +95 -0
- package/src/cli/index.ts +736 -0
- package/src/git/index.test.ts +92 -0
- package/src/git/index.ts +86 -0
- package/src/graph/types.test.ts +383 -0
- package/src/graph/types.ts +353 -0
- package/src/mcp/mcp.test.ts +176 -0
- package/src/mcp/server.ts +217 -0
- package/src/nextjs/index.ts +23 -0
- package/src/nextjs/nextjs.test.ts +233 -0
- package/src/nextjs/pages.ts +43 -0
- package/src/nextjs/react.ts +100 -0
- package/src/nextjs/router.ts +102 -0
- package/src/nextjs/routes.ts +69 -0
- package/src/opencode/index.test.ts +90 -0
- package/src/opencode/index.ts +83 -0
- package/src/parser/index.ts +339 -0
- package/src/parser/parser.test.ts +282 -0
- package/src/plan/index.test.ts +162 -0
- package/src/plan/index.ts +161 -0
- package/src/report/index.ts +128 -0
- package/src/scanner/index.ts +97 -0
- package/src/scanner/scanner.test.ts +135 -0
- package/src/search/index.ts +163 -0
- package/src/search/search.test.ts +512 -0
- package/src/traversal/index.ts +5 -0
- package/src/traversal/traversal.test.ts +266 -0
- package/src/traversal/traversal.ts +185 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +7 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# tsgraph — Project DNA
|
|
2
|
+
|
|
3
|
+
## Vision
|
|
4
|
+
A fast, local-only CLI tool that indexes Next.js / React / TypeScript codebases using AST
|
|
5
|
+
parsing into a queryable graph.json for AI coding agents. Equivalent to gograph but for TS.
|
|
6
|
+
Output is Markdown + JSON. No network calls, no telemetry, no SaaS backend.
|
|
7
|
+
|
|
8
|
+
## Design Philosophy (Go → TS Adaptation)
|
|
9
|
+
tsgraph is inspired by gograph (Go) but adapted for TypeScript/React/Next.js — NOT a blind copy.
|
|
10
|
+
Key language-driven differences:
|
|
11
|
+
- **Export model**: TS `export` keyword maps to `isExported`; class methods are always considered exported (default `public`)
|
|
12
|
+
- **No goroutines/channels** — replaced by async/promise/setTimeout concurrency
|
|
13
|
+
- **No struct tags** — TS has no native equivalent
|
|
14
|
+
- **Router detection** is Next.js App Router / Pages Router, not Gin/mux
|
|
15
|
+
- **React components** tracked via `isClientComponent` / `isServerComponent`
|
|
16
|
+
- **Interface satisfaction** is structural in TS — `ImplementsEdge` may be dropped if unused
|
|
17
|
+
- Go-specific concepts (structs with fields+tests, `MutationEdge`, `StructField.tags`) are present but may be removed if they don't earn their keep for TS
|
|
18
|
+
|
|
19
|
+
## Tech Stack
|
|
20
|
+
- Runtime: Node.js + tsx (dev) / tsc (build)
|
|
21
|
+
- AST: ts-morph (wraps TypeScript compiler API)
|
|
22
|
+
- CLI: commander
|
|
23
|
+
- MCP: @modelcontextprotocol/sdk
|
|
24
|
+
- Testing: vitest
|
|
25
|
+
- Linting: none (tsc strict mode is sufficient)
|
|
26
|
+
|
|
27
|
+
## Agent Rules
|
|
28
|
+
|
|
29
|
+
### Task Management
|
|
30
|
+
- READ TODOS.md at session start to know what's done and what's next
|
|
31
|
+
- UPDATE TODOS.md when you start/finish a task (`[.]` in-progress, `[x]` done)
|
|
32
|
+
- Work in phase order unless a task has no blockers
|
|
33
|
+
|
|
34
|
+
### Orchestration
|
|
35
|
+
- This is a single-orchestrator project. When a task has multiple independent
|
|
36
|
+
sub-tasks, delegate via the `task` tool (`subagent_type: general`) rather
|
|
37
|
+
than doing them sequentially.
|
|
38
|
+
- For each delegated sub-task, specify:
|
|
39
|
+
1. Exact files the sub-agent may modify
|
|
40
|
+
2. Which phase from TODOS.md it belongs to
|
|
41
|
+
3. What to return (never let sub-agents commit or merge)
|
|
42
|
+
- After all sub-tasks complete, run `npm run build && npm test` and fix
|
|
43
|
+
any issues directly. Do NOT re-delegate broken builds.
|
|
44
|
+
|
|
45
|
+
### Quality
|
|
46
|
+
- Run `npm run build` (tsc) AND `npm test` (vitest) after every task completion
|
|
47
|
+
- Fix all type errors and test failures before marking `[x]`
|
|
48
|
+
- If build is already broken when you start, note it in TODOS.md and fix it first
|
|
49
|
+
|
|
50
|
+
### Research
|
|
51
|
+
- Use webfetch when unsure about an API — check ts-morph docs, Next.js docs,
|
|
52
|
+
or reference gograph's Go source at https://github.com/ozgurcd/gograph
|
|
53
|
+
- DO NOT guess API signatures
|
|
54
|
+
|
|
55
|
+
### Code Style
|
|
56
|
+
- No comments in source files unless logic is non-obvious
|
|
57
|
+
- Named exports only (no default exports)
|
|
58
|
+
- Strict TypeScript everywhere, avoid `any`
|
|
59
|
+
- Follow patterns from adjacent files in the codebase
|
|
60
|
+
- No emojis in source code or commit messages
|
|
61
|
+
|
|
62
|
+
### Communication
|
|
63
|
+
- Be concise. Use TODOS.md for status, respond with only what's needed.
|
|
64
|
+
- If stuck, explain the blocker clearly rather than overthinking.
|
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# @shvmgyl15/tsgraph
|
|
2
|
+
|
|
3
|
+
A fast, local-only CLI tool that indexes TypeScript/React/Next.js codebases using AST parsing into a queryable graph.json for AI coding agents.
|
|
4
|
+
|
|
5
|
+
No network calls, no telemetry, no SaaS backend.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g @shvmgyl15/tsgraph
|
|
11
|
+
|
|
12
|
+
# Or use directly via npx:
|
|
13
|
+
npx @shvmgyl15/tsgraph build .
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Index your project
|
|
20
|
+
cd my-project
|
|
21
|
+
tsgraph build .
|
|
22
|
+
|
|
23
|
+
# Query the graph
|
|
24
|
+
tsgraph query "getUser" # search symbols
|
|
25
|
+
tsgraph callers "getUser" # who calls getUser
|
|
26
|
+
tsgraph callees "getUser" # what getUser calls
|
|
27
|
+
tsgraph node "getUser" # symbol details
|
|
28
|
+
tsgraph source "getUser" # symbol source code
|
|
29
|
+
|
|
30
|
+
# Analysis
|
|
31
|
+
tsgraph hotspots # files needing refactoring
|
|
32
|
+
tsgraph complexity --sort # cyclomatic complexity
|
|
33
|
+
tsgraph orphans # dead code detection
|
|
34
|
+
tsgraph coupling # package dependency coupling
|
|
35
|
+
|
|
36
|
+
# Traversal
|
|
37
|
+
tsgraph impact "getUser" # downstream blast radius
|
|
38
|
+
tsgraph path "foo" "bar" # shortest call path
|
|
39
|
+
tsgraph trace "error msg" # trace string literal upstream
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## All Commands
|
|
43
|
+
|
|
44
|
+
| Command | Description |
|
|
45
|
+
|---------|-------------|
|
|
46
|
+
| `build <root>` | Index project into `.tsgraph/graph.json` + `GRAPH_REPORT.md` |
|
|
47
|
+
| `callers <symbol>` | Show callers of a symbol |
|
|
48
|
+
| `callees <symbol>` | Show callees of a symbol |
|
|
49
|
+
| `node <symbol>` | Show symbol details |
|
|
50
|
+
| `source <symbol>` | Extract source code for a symbol |
|
|
51
|
+
| `query <pattern>` | Search symbols by pattern |
|
|
52
|
+
| `imports <path>` | Find files importing a package path |
|
|
53
|
+
| `public [package]` | List exported symbols |
|
|
54
|
+
| `focus <package>` | Show all assets for a package |
|
|
55
|
+
| `context <symbol>` | Bundle node + source + callers + callees |
|
|
56
|
+
| `complexity [file]` | Cyclomatic complexity analysis |
|
|
57
|
+
| `hotspot` | Rank files by complexity × size |
|
|
58
|
+
| `coupling` | Package coupling analysis |
|
|
59
|
+
| `deps <symbol>` | Call dependency tree |
|
|
60
|
+
| `impact <symbol>` | Downstream blast radius (BFS) |
|
|
61
|
+
| `path <from> <to>` | Shortest call path (BFS) |
|
|
62
|
+
| `orphans` | Dead code detection |
|
|
63
|
+
| `trace <string>` | String literal trace upstream |
|
|
64
|
+
| `boundaries` | Architecture enforcement via `.tsgraph/boundaries.json` |
|
|
65
|
+
| `changes [--base]` | Git-aware changed files and symbols |
|
|
66
|
+
| `stale [--days]` | Files not modified recently |
|
|
67
|
+
| `plan <files...>` | Change planning with blast radius |
|
|
68
|
+
| `review [--base]` | Code review summary |
|
|
69
|
+
| `add-opencode-plugin` | Configure opencode MCP + agent |
|
|
70
|
+
| `mcp` | Start MCP stdio server |
|
|
71
|
+
|
|
72
|
+
## Next.js Support
|
|
73
|
+
|
|
74
|
+
@shvmgyl15/tsgraph automatically detects Next.js project structure:
|
|
75
|
+
|
|
76
|
+
- **App Router**: `page.tsx`, `layout.tsx`, `loading.tsx`, `error.tsx`, `route.ts`
|
|
77
|
+
- **Pages Router**: `pages/` directory structure
|
|
78
|
+
- **Client/Server**: `'use client'` / `'use server'` directives
|
|
79
|
+
- **React Hooks**: detects hooks usage for client component inference
|
|
80
|
+
- **API Routes**: extracts route handlers from `route.ts` files
|
|
81
|
+
|
|
82
|
+
## Architecture Boundaries
|
|
83
|
+
|
|
84
|
+
Define layer rules in `.tsgraph/boundaries.json`:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"layers": [
|
|
89
|
+
{ "name": "ui", "path": "src/components", "dependsOn": ["shared"] },
|
|
90
|
+
{ "name": "shared", "path": "src/shared", "dependsOn": ["lib"] },
|
|
91
|
+
{ "name": "lib", "path": "src/lib", "dependsOn": [] }
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
tsgraph boundaries
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## AI Agent Integration
|
|
101
|
+
|
|
102
|
+
### opencode
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
tsgraph add-opencode-plugin
|
|
106
|
+
```
|
|
107
|
+
Updates `opencode.json` with the tsgraph MCP server and creates `.opencode/agents/tsgraph.json`.
|
|
108
|
+
|
|
109
|
+
### Claude / Any MCP Client
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
tsgraph mcp
|
|
113
|
+
```
|
|
114
|
+
Starts an MCP stdio server exposing all query/search commands as tools. Configure your MCP client to launch `tsgraph mcp` as a subprocess.
|
|
115
|
+
|
|
116
|
+
## Development
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
git clone https://github.com/shvmgyl15/tsgraph.git
|
|
120
|
+
cd tsgraph
|
|
121
|
+
npm install
|
|
122
|
+
npm run build
|
|
123
|
+
npm test
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
MIT
|
package/TODOS.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# tsgraph — Implementation Plan
|
|
2
|
+
|
|
3
|
+
## Phase 1: Project Scaffold
|
|
4
|
+
- [x] Update opencode.json with AGENTS.md reference
|
|
5
|
+
- [x] Create AGENTS.md with project DNA
|
|
6
|
+
- [x] Create TODOS.md (this file)
|
|
7
|
+
- [x] Initialize package.json with dependencies
|
|
8
|
+
- [x] Configure tsconfig.json (strict, ESNext)
|
|
9
|
+
- [x] Setup vitest config
|
|
10
|
+
- [x] Create src directory structure
|
|
11
|
+
|
|
12
|
+
## Phase 2: Core Data Model
|
|
13
|
+
- [x] Define graph types (Graph, PackageNode, FileNode, SymbolNode, etc.)
|
|
14
|
+
- [x] Add JSON serialization / deserialization
|
|
15
|
+
- [x] Write unit tests for graph types
|
|
16
|
+
|
|
17
|
+
## Phase 3: Scanner + Parser Core
|
|
18
|
+
- [x] Implement file scanner (walk tree, gitignore support, file classification)
|
|
19
|
+
- [x] Implement symbol extractor (ts-morph: functions, classes, interfaces, types, enums, vars)
|
|
20
|
+
- [x] Implement call expression extractor
|
|
21
|
+
- [x] Implement import edge + dependency (package.json) extractor
|
|
22
|
+
- [x] Wire up `build` command end-to-end
|
|
23
|
+
- [x] Write parser/scanner unit tests
|
|
24
|
+
|
|
25
|
+
## Phase 4: Query Commands
|
|
26
|
+
- [x] callers / callees
|
|
27
|
+
- [x] node / source / query
|
|
28
|
+
- [x] context (bundle — node + source + callers + callees + tests)
|
|
29
|
+
- [x] imports / public / focus
|
|
30
|
+
- [x] Write query command tests
|
|
31
|
+
|
|
32
|
+
## Phase 5: Next.js / React Extractors
|
|
33
|
+
- [x] App Router tree detection (page/layout/loading/error/route files)
|
|
34
|
+
- [x] Pages Router detection
|
|
35
|
+
- [x] 'use client' / 'use server' + hooks analysis
|
|
36
|
+
- [x] Route extraction from API / route handlers
|
|
37
|
+
- [x] Write extractor tests
|
|
38
|
+
|
|
39
|
+
## Phase 6: Analysis Commands
|
|
40
|
+
- [x] complexity (cyclomatic)
|
|
41
|
+
- [x] hotspot / coupling / deps
|
|
42
|
+
- [x] Write analysis tests
|
|
43
|
+
|
|
44
|
+
## Phase 7: Graph Traversal
|
|
45
|
+
- [x] impact (BFS downstream blast radius)
|
|
46
|
+
- [x] path (BFS shortest path between symbols)
|
|
47
|
+
- [x] orphans (dead code detection)
|
|
48
|
+
- [x] trace / errorflow (reverse BFS from string literal)
|
|
49
|
+
- [x] Write traversal tests
|
|
50
|
+
|
|
51
|
+
## Phase 8: MCP Server
|
|
52
|
+
- [x] MCP stdio server wrapping all query tools
|
|
53
|
+
- [x] Tool definition for each search/query command
|
|
54
|
+
- [x] MCP integration test
|
|
55
|
+
|
|
56
|
+
## Phase 9: Advanced Features
|
|
57
|
+
- [x] boundaries (architecture enforcement via .tsgraph/boundaries.json)
|
|
58
|
+
- [x] changes / stale (git-aware incremental analysis)
|
|
59
|
+
- [x] plan / review (change planning reports)
|
|
60
|
+
- [x] add-opencode-plugin (auto-configure opencode MCP + agent)
|
|
61
|
+
- [x] Enhanced GRAPH_REPORT.md (hotspots, boundaries, coupling, stale)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analysis.test.d.ts","sourceRoot":"","sources":["../../src/analysis/analysis.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import { makeGraph, makeSymbolNode, makeCallEdge, makeImportEdge, makeFileNode, } from "../graph/types.js";
|
|
6
|
+
import { cyclomaticComplexity, analyzeComplexity } from "./complexity.js";
|
|
7
|
+
import { findHotspots } from "./hotspot.js";
|
|
8
|
+
import { analyzeCoupling, dependencyTree } from "./coupling.js";
|
|
9
|
+
function createTempDir() {
|
|
10
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), "tsgraph-test-"));
|
|
11
|
+
}
|
|
12
|
+
describe("cyclomaticComplexity", () => {
|
|
13
|
+
it("returns 1 for a function with no branches", () => {
|
|
14
|
+
const code = `function greet() { return "hello"; }`;
|
|
15
|
+
expect(cyclomaticComplexity(code)).toBe(1);
|
|
16
|
+
});
|
|
17
|
+
it("counts if statements", () => {
|
|
18
|
+
const code = `function f() {
|
|
19
|
+
if (a) return 1;
|
|
20
|
+
if (b) return 2;
|
|
21
|
+
}`;
|
|
22
|
+
expect(cyclomaticComplexity(code)).toBe(3);
|
|
23
|
+
});
|
|
24
|
+
it("counts if-else as single branch point", () => {
|
|
25
|
+
const code = `function f() {
|
|
26
|
+
if (a) { return 1; }
|
|
27
|
+
else { return 2; }
|
|
28
|
+
}`;
|
|
29
|
+
expect(cyclomaticComplexity(code)).toBe(2);
|
|
30
|
+
});
|
|
31
|
+
it("counts else-if as additional branch", () => {
|
|
32
|
+
const code = `function f() {
|
|
33
|
+
if (a) { return 1; }
|
|
34
|
+
else if (b) { return 2; }
|
|
35
|
+
else { return 3; }
|
|
36
|
+
}`;
|
|
37
|
+
expect(cyclomaticComplexity(code)).toBe(3);
|
|
38
|
+
});
|
|
39
|
+
it("counts for loops", () => {
|
|
40
|
+
const code = `function f() {
|
|
41
|
+
for (let i = 0; i < 10; i++) {}
|
|
42
|
+
}`;
|
|
43
|
+
expect(cyclomaticComplexity(code)).toBe(2);
|
|
44
|
+
});
|
|
45
|
+
it("counts while loops", () => {
|
|
46
|
+
const code = `function f() {
|
|
47
|
+
while (true) { break; }
|
|
48
|
+
}`;
|
|
49
|
+
expect(cyclomaticComplexity(code)).toBe(2);
|
|
50
|
+
});
|
|
51
|
+
it("counts case labels", () => {
|
|
52
|
+
const code = `function f(x: number) {
|
|
53
|
+
switch (x) {
|
|
54
|
+
case 1: return "a";
|
|
55
|
+
case 2: return "b";
|
|
56
|
+
case 3: return "c";
|
|
57
|
+
}
|
|
58
|
+
}`;
|
|
59
|
+
expect(cyclomaticComplexity(code)).toBe(4);
|
|
60
|
+
});
|
|
61
|
+
it("counts catch clauses", () => {
|
|
62
|
+
const code = `function f() {
|
|
63
|
+
try { doStuff(); }
|
|
64
|
+
catch (e) { handle(); }
|
|
65
|
+
}`;
|
|
66
|
+
expect(cyclomaticComplexity(code)).toBe(2);
|
|
67
|
+
});
|
|
68
|
+
it("counts ternary operators", () => {
|
|
69
|
+
const code = `function f() {
|
|
70
|
+
return a ? b : c;
|
|
71
|
+
}`;
|
|
72
|
+
expect(cyclomaticComplexity(code)).toBe(2);
|
|
73
|
+
});
|
|
74
|
+
it("counts logical && and ||", () => {
|
|
75
|
+
const code = `function f() {
|
|
76
|
+
if (a && b || c) return 1;
|
|
77
|
+
}`;
|
|
78
|
+
expect(cyclomaticComplexity(code)).toBe(4);
|
|
79
|
+
});
|
|
80
|
+
it("avoids counting string literals", () => {
|
|
81
|
+
const code = `function f() {
|
|
82
|
+
const s = "if (true) { for(;;) {} }";
|
|
83
|
+
return s;
|
|
84
|
+
}`;
|
|
85
|
+
expect(cyclomaticComplexity(code)).toBe(1);
|
|
86
|
+
});
|
|
87
|
+
it("ignores comments", () => {
|
|
88
|
+
const code = `function f() {
|
|
89
|
+
// if (true) { return 1; }
|
|
90
|
+
/* for(;;) {} */
|
|
91
|
+
return 0;
|
|
92
|
+
}`;
|
|
93
|
+
expect(cyclomaticComplexity(code)).toBe(1);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe("analyzeComplexity", () => {
|
|
97
|
+
it("returns complexity for all functions in a project", () => {
|
|
98
|
+
const dir = createTempDir();
|
|
99
|
+
const filePath = path.join(dir, "src/lib.ts");
|
|
100
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
101
|
+
fs.writeFileSync(filePath, [
|
|
102
|
+
"export function simple() { return 1; }",
|
|
103
|
+
"export function complex() {",
|
|
104
|
+
" if (a) { for(;;) {} }",
|
|
105
|
+
" return 0;",
|
|
106
|
+
"}",
|
|
107
|
+
].join("\n"), "utf-8");
|
|
108
|
+
const graph = makeGraph({
|
|
109
|
+
root: dir,
|
|
110
|
+
files: [makeFileNode({ path: "src/lib.ts", lines: 5 })],
|
|
111
|
+
symbols: [
|
|
112
|
+
makeSymbolNode({
|
|
113
|
+
id: "simple",
|
|
114
|
+
name: "simple",
|
|
115
|
+
kind: "function",
|
|
116
|
+
file: "src/lib.ts",
|
|
117
|
+
line: 1,
|
|
118
|
+
endLine: 1,
|
|
119
|
+
packageName: "app",
|
|
120
|
+
isExported: true,
|
|
121
|
+
}),
|
|
122
|
+
makeSymbolNode({
|
|
123
|
+
id: "complex",
|
|
124
|
+
name: "complex",
|
|
125
|
+
kind: "function",
|
|
126
|
+
file: "src/lib.ts",
|
|
127
|
+
line: 2,
|
|
128
|
+
endLine: 5,
|
|
129
|
+
packageName: "app",
|
|
130
|
+
isExported: true,
|
|
131
|
+
}),
|
|
132
|
+
],
|
|
133
|
+
});
|
|
134
|
+
const results = analyzeComplexity(graph);
|
|
135
|
+
expect(results).toHaveLength(2);
|
|
136
|
+
const simple = results.find((r) => r.symbol.name === "simple");
|
|
137
|
+
const complex = results.find((r) => r.symbol.name === "complex");
|
|
138
|
+
expect(simple.complexity).toBe(1);
|
|
139
|
+
expect(complex.complexity).toBeGreaterThanOrEqual(2);
|
|
140
|
+
fs.rmSync(dir, { recursive: true });
|
|
141
|
+
});
|
|
142
|
+
it("filters by file when specified", () => {
|
|
143
|
+
const dir = createTempDir();
|
|
144
|
+
const filePath = path.join(dir, "src/a.ts");
|
|
145
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
146
|
+
fs.writeFileSync(filePath, "export function foo() {}", "utf-8");
|
|
147
|
+
const graph = makeGraph({
|
|
148
|
+
root: dir,
|
|
149
|
+
symbols: [
|
|
150
|
+
makeSymbolNode({
|
|
151
|
+
id: "foo",
|
|
152
|
+
name: "foo",
|
|
153
|
+
kind: "function",
|
|
154
|
+
file: "src/a.ts",
|
|
155
|
+
line: 1,
|
|
156
|
+
endLine: 1,
|
|
157
|
+
}),
|
|
158
|
+
makeSymbolNode({
|
|
159
|
+
id: "bar",
|
|
160
|
+
name: "bar",
|
|
161
|
+
kind: "function",
|
|
162
|
+
file: "src/b.ts",
|
|
163
|
+
line: 1,
|
|
164
|
+
endLine: 1,
|
|
165
|
+
}),
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
const results = analyzeComplexity(graph, "a.ts");
|
|
169
|
+
expect(results).toHaveLength(1);
|
|
170
|
+
expect(results[0].symbol.name).toBe("foo");
|
|
171
|
+
fs.rmSync(dir, { recursive: true });
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
describe("findHotspots", () => {
|
|
175
|
+
it("returns top hotspots sorted by score", () => {
|
|
176
|
+
const dir = createTempDir();
|
|
177
|
+
const filePath = path.join(dir, "src/hot.ts");
|
|
178
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
179
|
+
fs.writeFileSync(filePath, [
|
|
180
|
+
"export function a() {",
|
|
181
|
+
" if (x) { for(;;) {} }",
|
|
182
|
+
" if (y) { while(z) {} }",
|
|
183
|
+
" return 0;",
|
|
184
|
+
"}",
|
|
185
|
+
"export function b() { return 1; }",
|
|
186
|
+
].join("\n"), "utf-8");
|
|
187
|
+
const graph = makeGraph({
|
|
188
|
+
root: dir,
|
|
189
|
+
files: [makeFileNode({ path: "src/hot.ts", lines: 6 })],
|
|
190
|
+
symbols: [
|
|
191
|
+
makeSymbolNode({
|
|
192
|
+
id: "a",
|
|
193
|
+
name: "a",
|
|
194
|
+
kind: "function",
|
|
195
|
+
file: "src/hot.ts",
|
|
196
|
+
line: 1,
|
|
197
|
+
endLine: 5,
|
|
198
|
+
packageName: "app",
|
|
199
|
+
}),
|
|
200
|
+
makeSymbolNode({
|
|
201
|
+
id: "b",
|
|
202
|
+
name: "b",
|
|
203
|
+
kind: "function",
|
|
204
|
+
file: "src/hot.ts",
|
|
205
|
+
line: 6,
|
|
206
|
+
endLine: 6,
|
|
207
|
+
packageName: "app",
|
|
208
|
+
}),
|
|
209
|
+
],
|
|
210
|
+
});
|
|
211
|
+
const hotspots = findHotspots(graph, 5);
|
|
212
|
+
expect(hotspots.length).toBeGreaterThanOrEqual(1);
|
|
213
|
+
expect(hotspots[0].file).toBe("src/hot.ts");
|
|
214
|
+
fs.rmSync(dir, { recursive: true });
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
describe("analyzeCoupling", () => {
|
|
218
|
+
it("finds packages importing from other modules", () => {
|
|
219
|
+
const graph = makeGraph({
|
|
220
|
+
files: [
|
|
221
|
+
makeFileNode({ path: "src/orders.ts", packageName: "orders" }),
|
|
222
|
+
makeFileNode({ path: "src/payment.ts", packageName: "payment" }),
|
|
223
|
+
makeFileNode({ path: "src/notify.ts", packageName: "notify" }),
|
|
224
|
+
],
|
|
225
|
+
imports: [
|
|
226
|
+
makeImportEdge({
|
|
227
|
+
fromFile: "src/orders.ts",
|
|
228
|
+
fromPackage: "orders",
|
|
229
|
+
importPath: "payment",
|
|
230
|
+
alias: "payment",
|
|
231
|
+
isDefault: true,
|
|
232
|
+
}),
|
|
233
|
+
makeImportEdge({
|
|
234
|
+
fromFile: "src/orders.ts",
|
|
235
|
+
fromPackage: "orders",
|
|
236
|
+
importPath: "notify",
|
|
237
|
+
alias: "notify",
|
|
238
|
+
isDefault: true,
|
|
239
|
+
}),
|
|
240
|
+
makeImportEdge({
|
|
241
|
+
fromFile: "src/orders.ts",
|
|
242
|
+
fromPackage: "orders",
|
|
243
|
+
importPath: "payment",
|
|
244
|
+
alias: "processPayment",
|
|
245
|
+
isDefault: false,
|
|
246
|
+
}),
|
|
247
|
+
],
|
|
248
|
+
});
|
|
249
|
+
const results = analyzeCoupling(graph);
|
|
250
|
+
expect(results).toHaveLength(2);
|
|
251
|
+
const paymentCoupling = results.find((r) => r.coupledTo === "payment");
|
|
252
|
+
expect(paymentCoupling).toBeTruthy();
|
|
253
|
+
expect(paymentCoupling.importCount).toBe(2);
|
|
254
|
+
expect(paymentCoupling.packageName).toBe("orders");
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
describe("dependencyTree", () => {
|
|
258
|
+
it("builds a tree from call edges", () => {
|
|
259
|
+
const graph = makeGraph({
|
|
260
|
+
symbols: [
|
|
261
|
+
makeSymbolNode({
|
|
262
|
+
id: "src/main.ts::serve",
|
|
263
|
+
name: "serve",
|
|
264
|
+
kind: "function",
|
|
265
|
+
file: "src/main.ts",
|
|
266
|
+
line: 1,
|
|
267
|
+
endLine: 5,
|
|
268
|
+
packageName: "app",
|
|
269
|
+
}),
|
|
270
|
+
makeSymbolNode({
|
|
271
|
+
id: "src/main.ts::greet",
|
|
272
|
+
name: "greet",
|
|
273
|
+
kind: "function",
|
|
274
|
+
file: "src/main.ts",
|
|
275
|
+
line: 6,
|
|
276
|
+
endLine: 8,
|
|
277
|
+
packageName: "app",
|
|
278
|
+
}),
|
|
279
|
+
makeSymbolNode({
|
|
280
|
+
id: "src/main.ts::log",
|
|
281
|
+
name: "log",
|
|
282
|
+
kind: "function",
|
|
283
|
+
file: "src/main.ts",
|
|
284
|
+
line: 9,
|
|
285
|
+
endLine: 11,
|
|
286
|
+
packageName: "app",
|
|
287
|
+
}),
|
|
288
|
+
],
|
|
289
|
+
calls: [
|
|
290
|
+
makeCallEdge({
|
|
291
|
+
callerSymbolId: "src/main.ts::serve",
|
|
292
|
+
callerName: "serve",
|
|
293
|
+
calleeRaw: "greet",
|
|
294
|
+
file: "src/main.ts",
|
|
295
|
+
line: 3,
|
|
296
|
+
}),
|
|
297
|
+
makeCallEdge({
|
|
298
|
+
callerSymbolId: "src/main.ts::serve",
|
|
299
|
+
callerName: "serve",
|
|
300
|
+
calleeRaw: "log",
|
|
301
|
+
file: "src/main.ts",
|
|
302
|
+
line: 4,
|
|
303
|
+
}),
|
|
304
|
+
],
|
|
305
|
+
});
|
|
306
|
+
const tree = dependencyTree(graph, "serve");
|
|
307
|
+
expect(tree).toBeTruthy();
|
|
308
|
+
expect(tree.name).toBe("serve");
|
|
309
|
+
expect(tree.children).toHaveLength(2);
|
|
310
|
+
const childNames = tree.children.map((c) => c.name).sort();
|
|
311
|
+
expect(childNames).toEqual(["greet", "log"]);
|
|
312
|
+
});
|
|
313
|
+
it("returns undefined for unknown symbol", () => {
|
|
314
|
+
const graph = makeGraph();
|
|
315
|
+
const tree = dependencyTree(graph, "noop");
|
|
316
|
+
expect(tree).toBeUndefined();
|
|
317
|
+
});
|
|
318
|
+
it("respects max depth", () => {
|
|
319
|
+
const graph = makeGraph({
|
|
320
|
+
symbols: [
|
|
321
|
+
makeSymbolNode({
|
|
322
|
+
id: "a",
|
|
323
|
+
name: "a",
|
|
324
|
+
kind: "function",
|
|
325
|
+
file: "a.ts",
|
|
326
|
+
line: 1,
|
|
327
|
+
endLine: 1,
|
|
328
|
+
packageName: "app",
|
|
329
|
+
}),
|
|
330
|
+
makeSymbolNode({
|
|
331
|
+
id: "b",
|
|
332
|
+
name: "b",
|
|
333
|
+
kind: "function",
|
|
334
|
+
file: "b.ts",
|
|
335
|
+
line: 1,
|
|
336
|
+
endLine: 1,
|
|
337
|
+
packageName: "app",
|
|
338
|
+
}),
|
|
339
|
+
makeSymbolNode({
|
|
340
|
+
id: "c",
|
|
341
|
+
name: "c",
|
|
342
|
+
kind: "function",
|
|
343
|
+
file: "c.ts",
|
|
344
|
+
line: 1,
|
|
345
|
+
endLine: 1,
|
|
346
|
+
packageName: "app",
|
|
347
|
+
}),
|
|
348
|
+
],
|
|
349
|
+
calls: [
|
|
350
|
+
makeCallEdge({ callerSymbolId: "a", callerName: "a", calleeRaw: "b", file: "a.ts", line: 1 }),
|
|
351
|
+
makeCallEdge({ callerSymbolId: "b", callerName: "b", calleeRaw: "c", file: "b.ts", line: 1 }),
|
|
352
|
+
],
|
|
353
|
+
});
|
|
354
|
+
const tree = dependencyTree(graph, "a", 1);
|
|
355
|
+
expect(tree.children).toHaveLength(1);
|
|
356
|
+
expect(tree.children[0].children).toHaveLength(0);
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
//# sourceMappingURL=analysis.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analysis.test.js","sourceRoot":"","sources":["../../src/analysis/analysis.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Graph, SymbolNode } from "../graph/types.js";
|
|
2
|
+
export declare function cyclomaticComplexity(sourceCode: string): number;
|
|
3
|
+
export interface ComplexityResult {
|
|
4
|
+
symbol: SymbolNode;
|
|
5
|
+
complexity: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function analyzeComplexity(graph: Graph, fileFilter?: string): ComplexityResult[];
|
|
8
|
+
//# sourceMappingURL=complexity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complexity.d.ts","sourceRoot":"","sources":["../../src/analysis/complexity.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AA+C3D,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAwB/D;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,UAAU,CAAC,EAAE,MAAM,GAClB,gBAAgB,EAAE,CAuBpB"}
|