@mishasinitcyn/betterrank 0.1.0 → 0.1.2
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/LICENSE +21 -0
- package/README.md +168 -0
- package/package.json +1 -1
- package/src/cli.js +6 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Misha Sinitcyn
|
|
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 FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# BetterRank
|
|
2
|
+
|
|
3
|
+
Structural code index with PageRank-ranked repo maps, symbol search, call-graph queries, and dependency analysis. Built on [tree-sitter](https://tree-sitter.github.io/) and [graphology](https://graphology.github.io/).
|
|
4
|
+
|
|
5
|
+
BetterRank parses your source files, builds a dependency graph, and ranks every symbol by structural importance using PageRank. Instead of grepping through thousands of files, ask questions like "what are the most important functions in this project?" or "who calls this function?" and get ranked, structured answers in seconds.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g @mishasinitcyn/betterrank
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Get a ranked overview of any project
|
|
17
|
+
betterrank map --root /path/to/project
|
|
18
|
+
|
|
19
|
+
# Search for symbols by name or parameter
|
|
20
|
+
betterrank search auth --root /path/to/project
|
|
21
|
+
|
|
22
|
+
# Who calls this function?
|
|
23
|
+
betterrank callers authenticateUser --root /path/to/project
|
|
24
|
+
|
|
25
|
+
# What depends on this file?
|
|
26
|
+
betterrank dependents src/auth/handlers.ts --root /path/to/project
|
|
27
|
+
|
|
28
|
+
# What does this file import?
|
|
29
|
+
betterrank deps src/auth/handlers.ts --root /path/to/project
|
|
30
|
+
|
|
31
|
+
# Local subgraph around a file
|
|
32
|
+
betterrank neighborhood src/auth/handlers.ts --root /path/to/project --limit 10
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## How It Works
|
|
36
|
+
|
|
37
|
+
1. **Parse**: Native tree-sitter extracts definitions (functions, classes, types) and references (calls, imports) from source files
|
|
38
|
+
2. **Graph**: graphology MultiDirectedGraph with typed edges (DEFINES, REFERENCES, IMPORTS)
|
|
39
|
+
3. **Rank**: PageRank scores every symbol by structural importance — heavily-imported utilities rank higher than leaf files
|
|
40
|
+
4. **Cache**: mtime-based incremental updates. Only re-parses changed files. Cache lives at the platform cache directory (`~/Library/Caches/code-index/` on macOS, `~/.cache/code-index/` on Linux)
|
|
41
|
+
|
|
42
|
+
## Supported Languages
|
|
43
|
+
|
|
44
|
+
JavaScript, TypeScript, Python, Rust, Go, Java, Ruby, C, C++, C#, PHP
|
|
45
|
+
|
|
46
|
+
## Commands
|
|
47
|
+
|
|
48
|
+
### `map` — Repo map
|
|
49
|
+
|
|
50
|
+
Summary of the most structurally important definitions, ranked by PageRank. Default limit is 50 symbols.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
betterrank map --root /path/to/project
|
|
54
|
+
betterrank map --root /path/to/project --limit 100
|
|
55
|
+
betterrank map --root /path/to/project --focus src/api/auth.ts,src/api/login.ts
|
|
56
|
+
betterrank map --root /path/to/project --count
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### `search` — Find symbols by name or signature
|
|
60
|
+
|
|
61
|
+
Substring search across symbol names **and** full function signatures (including parameter names and types). Results ranked by PageRank.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
betterrank search encrypt --root /path/to/project
|
|
65
|
+
betterrank search max_age --root /path/to/project # matches param names too
|
|
66
|
+
betterrank search imp --root /path/to/project --kind function
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### `symbols` — List definitions
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
betterrank symbols --root /path/to/project
|
|
73
|
+
betterrank symbols --root /path/to/project --file src/auth.ts
|
|
74
|
+
betterrank symbols --root /path/to/project --kind function
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `callers` — Who calls this symbol
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
betterrank callers authenticateUser --root /path/to/project
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `deps` — What does this file import
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
betterrank deps src/auth.ts --root /path/to/project
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### `dependents` — What imports this file
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
betterrank dependents src/auth.ts --root /path/to/project
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `neighborhood` — Local subgraph around a file
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
betterrank neighborhood src/auth.ts --root /path/to/project --count
|
|
99
|
+
betterrank neighborhood src/auth.ts --root /path/to/project --hops 2 --limit 10
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `structure` — File tree with symbol counts
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
betterrank structure --root /path/to/project --depth 3
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `reindex` — Force full rebuild
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
betterrank reindex --root /path/to/project
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `stats` — Index statistics
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
betterrank stats --root /path/to/project
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Global Flags
|
|
121
|
+
|
|
122
|
+
| Flag | Description |
|
|
123
|
+
|---|---|
|
|
124
|
+
| `--root <path>` | Project root. **Always pass this explicitly.** |
|
|
125
|
+
| `--count` | Return counts only (no content) |
|
|
126
|
+
| `--offset N` | Skip first N results |
|
|
127
|
+
| `--limit N` | Max results to return (default: 50) |
|
|
128
|
+
|
|
129
|
+
## Programmatic API
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
import { CodeIndex } from '@mishasinitcyn/betterrank';
|
|
133
|
+
|
|
134
|
+
const idx = new CodeIndex('/path/to/project');
|
|
135
|
+
|
|
136
|
+
const map = await idx.map({ limit: 100, focusFiles: ['src/main.ts'] });
|
|
137
|
+
const results = await idx.search({ query: 'auth', kind: 'function', limit: 10 });
|
|
138
|
+
const callers = await idx.callers({ symbol: 'authenticate' });
|
|
139
|
+
const deps = await idx.dependencies({ file: 'src/auth.ts' });
|
|
140
|
+
const dependents = await idx.dependents({ file: 'src/auth.ts' });
|
|
141
|
+
const hood = await idx.neighborhood({ file: 'src/auth.ts', hops: 2, maxFiles: 10 });
|
|
142
|
+
|
|
143
|
+
const stats = await idx.stats();
|
|
144
|
+
await idx.reindex();
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Ignore Configuration
|
|
148
|
+
|
|
149
|
+
Built-in defaults ignore `node_modules`, `dist`, `build`, `.venv`, etc. To add project-specific ignores, create `<project-root>/.code-index/config.json`:
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"ignore": ["experiments/**", "legacy/**"]
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Cache
|
|
158
|
+
|
|
159
|
+
Cache lives at the platform cache directory:
|
|
160
|
+
- **macOS**: `~/Library/Caches/code-index/`
|
|
161
|
+
- **Linux**: `~/.cache/code-index/`
|
|
162
|
+
- **Windows**: `%LOCALAPPDATA%/code-index/Cache/`
|
|
163
|
+
|
|
164
|
+
Override with `CODE_INDEX_CACHE_DIR` env var. Cache files are disposable — delete anytime, they rebuild automatically.
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mishasinitcyn/betterrank",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Structural code index with PageRank-ranked repo maps, symbol search, call-graph queries, and dependency analysis. Built on tree-sitter and graphology.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ const DEFAULT_LIMIT = 50;
|
|
|
7
7
|
const DEFAULT_DEPTH = 3;
|
|
8
8
|
|
|
9
9
|
const USAGE = `
|
|
10
|
-
|
|
10
|
+
betterrank <command> [options]
|
|
11
11
|
|
|
12
12
|
Commands:
|
|
13
13
|
map [--focus file1,file2] Repo map (ranked by PageRank)
|
|
@@ -78,7 +78,7 @@ async function main() {
|
|
|
78
78
|
|
|
79
79
|
case 'search': {
|
|
80
80
|
const query = flags._positional[0];
|
|
81
|
-
if (!query) { console.error('Usage:
|
|
81
|
+
if (!query) { console.error('Usage: betterrank search <query> [--kind type]'); process.exit(1); }
|
|
82
82
|
const effectiveLimit = countMode ? undefined : (userLimit !== undefined ? userLimit : DEFAULT_LIMIT);
|
|
83
83
|
const result = await idx.search({ query, kind: flags.kind, count: countMode, offset, limit: effectiveLimit });
|
|
84
84
|
if (countMode) {
|
|
@@ -126,7 +126,7 @@ async function main() {
|
|
|
126
126
|
|
|
127
127
|
case 'callers': {
|
|
128
128
|
const symbol = flags._positional[0];
|
|
129
|
-
if (!symbol) { console.error('Usage:
|
|
129
|
+
if (!symbol) { console.error('Usage: betterrank callers <symbol> [--file path]'); process.exit(1); }
|
|
130
130
|
const effectiveLimit = countMode ? undefined : (userLimit !== undefined ? userLimit : DEFAULT_LIMIT);
|
|
131
131
|
const result = await idx.callers({ symbol, file: normalizeFilePath(flags.file), count: countMode, offset, limit: effectiveLimit });
|
|
132
132
|
if (countMode) {
|
|
@@ -146,7 +146,7 @@ async function main() {
|
|
|
146
146
|
|
|
147
147
|
case 'deps': {
|
|
148
148
|
const file = normalizeFilePath(flags._positional[0]);
|
|
149
|
-
if (!file) { console.error('Usage:
|
|
149
|
+
if (!file) { console.error('Usage: betterrank deps <file>'); process.exit(1); }
|
|
150
150
|
const effectiveLimit = countMode ? undefined : (userLimit !== undefined ? userLimit : DEFAULT_LIMIT);
|
|
151
151
|
const result = await idx.dependencies({ file, count: countMode, offset, limit: effectiveLimit });
|
|
152
152
|
if (countMode) {
|
|
@@ -164,7 +164,7 @@ async function main() {
|
|
|
164
164
|
|
|
165
165
|
case 'dependents': {
|
|
166
166
|
const file = normalizeFilePath(flags._positional[0]);
|
|
167
|
-
if (!file) { console.error('Usage:
|
|
167
|
+
if (!file) { console.error('Usage: betterrank dependents <file>'); process.exit(1); }
|
|
168
168
|
const effectiveLimit = countMode ? undefined : (userLimit !== undefined ? userLimit : DEFAULT_LIMIT);
|
|
169
169
|
const result = await idx.dependents({ file, count: countMode, offset, limit: effectiveLimit });
|
|
170
170
|
if (countMode) {
|
|
@@ -182,7 +182,7 @@ async function main() {
|
|
|
182
182
|
|
|
183
183
|
case 'neighborhood': {
|
|
184
184
|
const file = normalizeFilePath(flags._positional[0]);
|
|
185
|
-
if (!file) { console.error('Usage:
|
|
185
|
+
if (!file) { console.error('Usage: betterrank neighborhood <file> [--hops N] [--max-files N]'); process.exit(1); }
|
|
186
186
|
const hops = parseInt(flags.hops || '2', 10);
|
|
187
187
|
const maxFilesFlag = flags['max-files'] ? parseInt(flags['max-files'], 10) : 15;
|
|
188
188
|
|