@mishasinitcyn/betterrank 0.1.7 → 0.1.9
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/package.json +1 -1
- package/src/cache.js +17 -4
- package/src/cli.js +295 -8
- package/src/index.js +320 -9
- package/src/server.js +27 -0
- package/src/ui.html +430 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mishasinitcyn/betterrank",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
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/cache.js
CHANGED
|
@@ -150,7 +150,7 @@ class CodeIndexCache {
|
|
|
150
150
|
this.initialized = true;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
const { changed, deleted } = await this._getChangedFiles();
|
|
153
|
+
const { changed, deleted, totalScanned } = await this._getChangedFiles();
|
|
154
154
|
|
|
155
155
|
if (changed.length === 0 && deleted.length === 0) {
|
|
156
156
|
if (!this.graph) {
|
|
@@ -159,9 +159,15 @@ class CodeIndexCache {
|
|
|
159
159
|
const MDG = graphology.default?.MultiDirectedGraph || graphology.MultiDirectedGraph;
|
|
160
160
|
this.graph = new MDG({ allowSelfLoops: false });
|
|
161
161
|
}
|
|
162
|
-
return { changed: 0, deleted: 0 };
|
|
162
|
+
return { changed: 0, deleted: 0, totalScanned };
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
const isColdStart = !this.graph;
|
|
166
|
+
if (isColdStart) {
|
|
167
|
+
process.stderr.write(`Indexing ${this.projectRoot}... ${changed.length} files found, parsing...\n`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const t0 = Date.now();
|
|
165
171
|
const newSymbols = await this._parseFiles(changed);
|
|
166
172
|
|
|
167
173
|
if (!this.graph) {
|
|
@@ -175,7 +181,14 @@ class CodeIndexCache {
|
|
|
175
181
|
|
|
176
182
|
await saveGraph(this.graph, this.mtimes, this.cachePath);
|
|
177
183
|
|
|
178
|
-
|
|
184
|
+
if (isColdStart) {
|
|
185
|
+
const elapsed = ((Date.now() - t0) / 1000).toFixed(1);
|
|
186
|
+
let symbols = 0;
|
|
187
|
+
this.graph.forEachNode((_n, attrs) => { if (attrs.type === 'symbol') symbols++; });
|
|
188
|
+
process.stderr.write(`Indexed ${changed.length} files (${symbols} symbols, ${this.graph.size} edges) in ${elapsed}s\n`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return { changed: changed.length, deleted: deleted.length, totalScanned };
|
|
179
192
|
}
|
|
180
193
|
|
|
181
194
|
/**
|
|
@@ -256,7 +269,7 @@ class CodeIndexCache {
|
|
|
256
269
|
}
|
|
257
270
|
}
|
|
258
271
|
|
|
259
|
-
return { changed, deleted };
|
|
272
|
+
return { changed, deleted, totalScanned: files.length };
|
|
260
273
|
}
|
|
261
274
|
|
|
262
275
|
/**
|
package/src/cli.js
CHANGED
|
@@ -19,6 +19,7 @@ Commands:
|
|
|
19
19
|
deps <file> What this file imports (ranked)
|
|
20
20
|
dependents <file> What imports this file (ranked)
|
|
21
21
|
neighborhood <file> [--hops N] [--max-files N] Local subgraph (ranked by PageRank)
|
|
22
|
+
orphans [--level file|symbol] [--kind type] Find disconnected files/symbols
|
|
22
23
|
reindex Force full rebuild
|
|
23
24
|
stats Index statistics
|
|
24
25
|
|
|
@@ -27,8 +28,176 @@ Global flags:
|
|
|
27
28
|
--count Return counts only (no content)
|
|
28
29
|
--offset N Skip first N results
|
|
29
30
|
--limit N Max results to return (default: ${DEFAULT_LIMIT} for list commands)
|
|
31
|
+
--help Show help for a command (e.g. betterrank search --help)
|
|
30
32
|
`.trim();
|
|
31
33
|
|
|
34
|
+
const COMMAND_HELP = {
|
|
35
|
+
map: `betterrank map [--focus file1,file2] [--root <path>]
|
|
36
|
+
|
|
37
|
+
Aider-style repo map: the most structurally important definitions ranked by PageRank.
|
|
38
|
+
|
|
39
|
+
Options:
|
|
40
|
+
--focus <files> Comma-separated files to bias ranking toward
|
|
41
|
+
--count Return total symbol count only
|
|
42
|
+
--offset N Skip first N symbols
|
|
43
|
+
--limit N Max symbols to return (default: ${DEFAULT_LIMIT})
|
|
44
|
+
|
|
45
|
+
Examples:
|
|
46
|
+
betterrank map --root ./backend
|
|
47
|
+
betterrank map --root ./frontend --limit 100
|
|
48
|
+
betterrank map --root ./backend --focus src/auth/handlers.ts,src/api/login.ts`,
|
|
49
|
+
|
|
50
|
+
search: `betterrank search <query> [--kind type] [--root <path>]
|
|
51
|
+
|
|
52
|
+
Substring search on symbol names + full signatures (param names, types, defaults).
|
|
53
|
+
Results ranked by PageRank (most structurally important first).
|
|
54
|
+
|
|
55
|
+
Options:
|
|
56
|
+
--kind <type> Filter: function, class, type, variable, namespace, import
|
|
57
|
+
--count Return match count only
|
|
58
|
+
--offset N Skip first N results
|
|
59
|
+
--limit N Max results (default: ${DEFAULT_LIMIT})
|
|
60
|
+
|
|
61
|
+
Tips:
|
|
62
|
+
Use short substrings (3-5 chars) — PageRank ranking handles noise.
|
|
63
|
+
"imp" finds encrypt_imp_payload, increment_impression, etc.
|
|
64
|
+
Searches match against both symbol names AND full signatures (param names, types).
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
betterrank search resolve --root ./backend
|
|
68
|
+
betterrank search auth --kind function --limit 10
|
|
69
|
+
betterrank search max_age --root . --count`,
|
|
70
|
+
|
|
71
|
+
structure: `betterrank structure [--depth N] [--root <path>]
|
|
72
|
+
|
|
73
|
+
File tree with symbol counts per file.
|
|
74
|
+
|
|
75
|
+
Options:
|
|
76
|
+
--depth N Max directory depth (default: ${DEFAULT_DEPTH})
|
|
77
|
+
|
|
78
|
+
Examples:
|
|
79
|
+
betterrank structure --root ./backend --depth 2`,
|
|
80
|
+
|
|
81
|
+
symbols: `betterrank symbols [--file path] [--kind type] [--root <path>]
|
|
82
|
+
|
|
83
|
+
List symbol definitions, optionally filtered by file or kind.
|
|
84
|
+
Results ranked by PageRank (most structurally important first).
|
|
85
|
+
|
|
86
|
+
Options:
|
|
87
|
+
--file <path> Filter to a specific file (relative to --root)
|
|
88
|
+
--kind <type> Filter: function, class, type, variable, namespace, import
|
|
89
|
+
--count Return count only
|
|
90
|
+
--offset N Skip first N results
|
|
91
|
+
--limit N Max results (default: ${DEFAULT_LIMIT})
|
|
92
|
+
|
|
93
|
+
Examples:
|
|
94
|
+
betterrank symbols --file src/auth/handlers.ts --root ./backend
|
|
95
|
+
betterrank symbols --kind class --root . --limit 20`,
|
|
96
|
+
|
|
97
|
+
callers: `betterrank callers <symbol> [--file path] [--root <path>]
|
|
98
|
+
|
|
99
|
+
Find all files that reference a symbol. Ranked by file-level PageRank.
|
|
100
|
+
|
|
101
|
+
Options:
|
|
102
|
+
--file <path> Disambiguate when multiple symbols share a name
|
|
103
|
+
--count Return count only
|
|
104
|
+
--offset N Skip first N results
|
|
105
|
+
--limit N Max results (default: ${DEFAULT_LIMIT})
|
|
106
|
+
|
|
107
|
+
Examples:
|
|
108
|
+
betterrank callers authenticateUser --root ./backend
|
|
109
|
+
betterrank callers resolve --file src/utils.ts --root .`,
|
|
110
|
+
|
|
111
|
+
deps: `betterrank deps <file> [--root <path>]
|
|
112
|
+
|
|
113
|
+
What this file imports / depends on. Ranked by PageRank.
|
|
114
|
+
|
|
115
|
+
Options:
|
|
116
|
+
--count Return count only
|
|
117
|
+
--offset N Skip first N results
|
|
118
|
+
--limit N Max results (default: ${DEFAULT_LIMIT})
|
|
119
|
+
|
|
120
|
+
Examples:
|
|
121
|
+
betterrank deps src/auth/handlers.ts --root ./backend`,
|
|
122
|
+
|
|
123
|
+
dependents: `betterrank dependents <file> [--root <path>]
|
|
124
|
+
|
|
125
|
+
What files import this file. Ranked by PageRank.
|
|
126
|
+
|
|
127
|
+
Options:
|
|
128
|
+
--count Return count only
|
|
129
|
+
--offset N Skip first N results
|
|
130
|
+
--limit N Max results (default: ${DEFAULT_LIMIT})
|
|
131
|
+
|
|
132
|
+
Examples:
|
|
133
|
+
betterrank dependents src/auth/handlers.ts --root ./backend`,
|
|
134
|
+
|
|
135
|
+
neighborhood: `betterrank neighborhood <file> [--hops N] [--max-files N] [--root <path>]
|
|
136
|
+
|
|
137
|
+
Local subgraph around a file: its imports, importers, and their symbols.
|
|
138
|
+
|
|
139
|
+
Options:
|
|
140
|
+
--hops N BFS depth for outgoing imports (default: 2)
|
|
141
|
+
--max-files N Max files to include (default: 15, direct neighbors always included)
|
|
142
|
+
--count Return counts only
|
|
143
|
+
--offset N Skip first N files
|
|
144
|
+
--limit N Max files to return
|
|
145
|
+
|
|
146
|
+
Examples:
|
|
147
|
+
betterrank neighborhood src/auth/handlers.ts --root ./backend
|
|
148
|
+
betterrank neighborhood src/api/bid.js --hops 3 --max-files 20 --root .`,
|
|
149
|
+
|
|
150
|
+
orphans: `betterrank orphans [--level file|symbol] [--kind type] [--root <path>]
|
|
151
|
+
|
|
152
|
+
Find disconnected files or symbols — the "satellites" in the graph UI.
|
|
153
|
+
|
|
154
|
+
Levels:
|
|
155
|
+
file Files with zero cross-file imports (default)
|
|
156
|
+
symbol Symbols never referenced from outside their own file (dead code candidates)
|
|
157
|
+
|
|
158
|
+
Options:
|
|
159
|
+
--level <type> "file" or "symbol" (default: file)
|
|
160
|
+
--kind <type> Filter symbols: function, class, type, variable (only with --level symbol)
|
|
161
|
+
--count Return count only
|
|
162
|
+
--offset N Skip first N results
|
|
163
|
+
--limit N Max results (default: ${DEFAULT_LIMIT})
|
|
164
|
+
|
|
165
|
+
False positives (entry points, config files, tests, framework hooks, dunders,
|
|
166
|
+
etc.) are automatically excluded.
|
|
167
|
+
|
|
168
|
+
Examples:
|
|
169
|
+
betterrank orphans --root ./backend
|
|
170
|
+
betterrank orphans --level symbol --root .
|
|
171
|
+
betterrank orphans --level symbol --kind function --root .
|
|
172
|
+
betterrank orphans --count --root .`,
|
|
173
|
+
|
|
174
|
+
reindex: `betterrank reindex [--root <path>]
|
|
175
|
+
|
|
176
|
+
Force a full rebuild of the index. Use after branch switches, large merges,
|
|
177
|
+
or if results seem stale.
|
|
178
|
+
|
|
179
|
+
Examples:
|
|
180
|
+
betterrank reindex --root ./backend`,
|
|
181
|
+
|
|
182
|
+
stats: `betterrank stats [--root <path>]
|
|
183
|
+
|
|
184
|
+
Show index statistics: file count, symbol count, edge count.
|
|
185
|
+
|
|
186
|
+
Examples:
|
|
187
|
+
betterrank stats --root .`,
|
|
188
|
+
|
|
189
|
+
ui: `betterrank ui [--port N]
|
|
190
|
+
|
|
191
|
+
Launch the interactive web UI for exploring the index.
|
|
192
|
+
|
|
193
|
+
Options:
|
|
194
|
+
--port N Port to listen on (default: 3333)
|
|
195
|
+
|
|
196
|
+
Examples:
|
|
197
|
+
betterrank ui
|
|
198
|
+
betterrank ui --port 8080`,
|
|
199
|
+
};
|
|
200
|
+
|
|
32
201
|
async function main() {
|
|
33
202
|
const args = process.argv.slice(2);
|
|
34
203
|
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
@@ -39,6 +208,16 @@ async function main() {
|
|
|
39
208
|
const command = args[0];
|
|
40
209
|
const flags = parseFlags(args.slice(1));
|
|
41
210
|
|
|
211
|
+
// Per-command --help
|
|
212
|
+
if (flags.help === true || flags.h === true) {
|
|
213
|
+
if (COMMAND_HELP[command]) {
|
|
214
|
+
console.log(COMMAND_HELP[command]);
|
|
215
|
+
} else {
|
|
216
|
+
console.log(USAGE);
|
|
217
|
+
}
|
|
218
|
+
process.exit(0);
|
|
219
|
+
}
|
|
220
|
+
|
|
42
221
|
// UI command doesn't need --root or a CodeIndex instance
|
|
43
222
|
if (command === 'ui') {
|
|
44
223
|
const { startServer } = await import('./server.js');
|
|
@@ -73,6 +252,35 @@ async function main() {
|
|
|
73
252
|
return rel;
|
|
74
253
|
}
|
|
75
254
|
|
|
255
|
+
/** Print file-not-found diagnostics and exit. Returns true if handled. */
|
|
256
|
+
function handleFileNotFound(result, filePath) {
|
|
257
|
+
if (!result || !result.fileNotFound) return false;
|
|
258
|
+
console.error(`File "${filePath}" not found in index.`);
|
|
259
|
+
if (result.suggestions && result.suggestions.length > 0) {
|
|
260
|
+
console.error(`Did you mean:`);
|
|
261
|
+
for (const s of result.suggestions) console.error(` ${s}`);
|
|
262
|
+
}
|
|
263
|
+
console.error(`Tip: File paths are relative to --root. Use \`betterrank structure\` to see indexed files.`);
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** Suggest shorter query alternatives by splitting on _ and camelCase boundaries. */
|
|
268
|
+
function suggestShorterQueries(query) {
|
|
269
|
+
const parts = new Set();
|
|
270
|
+
// Split on underscores
|
|
271
|
+
for (const p of query.split('_')) {
|
|
272
|
+
if (p.length >= 3) parts.add(p.toLowerCase());
|
|
273
|
+
}
|
|
274
|
+
// Split on camelCase boundaries
|
|
275
|
+
const camelParts = query.replace(/([a-z])([A-Z])/g, '$1_$2').split('_');
|
|
276
|
+
for (const p of camelParts) {
|
|
277
|
+
if (p.length >= 3) parts.add(p.toLowerCase());
|
|
278
|
+
}
|
|
279
|
+
// Remove the original query itself
|
|
280
|
+
parts.delete(query.toLowerCase());
|
|
281
|
+
return [...parts].slice(0, 4);
|
|
282
|
+
}
|
|
283
|
+
|
|
76
284
|
switch (command) {
|
|
77
285
|
case 'map': {
|
|
78
286
|
const focusFiles = flags.focus ? flags.focus.split(',') : [];
|
|
@@ -87,6 +295,17 @@ async function main() {
|
|
|
87
295
|
console.log(`Use --limit N to show more, or --count for totals`);
|
|
88
296
|
}
|
|
89
297
|
}
|
|
298
|
+
// Diagnostics on empty index
|
|
299
|
+
if (result.diagnostics) {
|
|
300
|
+
const d = result.diagnostics;
|
|
301
|
+
console.log(`\nDiagnostics:`);
|
|
302
|
+
console.log(` Root: ${d.root}`);
|
|
303
|
+
console.log(` Files found: ${d.filesScanned}`);
|
|
304
|
+
console.log(` Extensions: ${d.extensions}`);
|
|
305
|
+
if (d.filesScanned === 0) {
|
|
306
|
+
console.log(` Tip: No supported files found. Try a broader --root.`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
90
309
|
break;
|
|
91
310
|
}
|
|
92
311
|
|
|
@@ -102,7 +321,17 @@ async function main() {
|
|
|
102
321
|
console.log(`${s.file}:${s.lineStart} [${s.kind}] ${s.signature}`);
|
|
103
322
|
}
|
|
104
323
|
if (result.length === 0) {
|
|
105
|
-
|
|
324
|
+
const st = await idx.stats();
|
|
325
|
+
console.log(`(no matches for "${query}")`);
|
|
326
|
+
if (st.symbols > 0) {
|
|
327
|
+
console.log(`Index has ${st.symbols.toLocaleString()} symbols across ${st.files.toLocaleString()} files.`);
|
|
328
|
+
const suggestions = suggestShorterQueries(query);
|
|
329
|
+
if (suggestions.length > 0) {
|
|
330
|
+
console.log(`Tip: Use shorter substrings. Try: ${suggestions.map(s => `"${s}"`).join(', ')}`);
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
console.log(`Index is empty. Check --root or run: betterrank map --root <path>`);
|
|
334
|
+
}
|
|
106
335
|
} else if (result.length === effectiveLimit && userLimit === undefined) {
|
|
107
336
|
console.log(`\n(showing top ${effectiveLimit} by relevance — use --limit N or --count for total)`);
|
|
108
337
|
}
|
|
@@ -163,13 +392,15 @@ async function main() {
|
|
|
163
392
|
if (!file) { console.error('Usage: betterrank deps <file>'); process.exit(1); }
|
|
164
393
|
const effectiveLimit = countMode ? undefined : (userLimit !== undefined ? userLimit : DEFAULT_LIMIT);
|
|
165
394
|
const result = await idx.dependencies({ file, count: countMode, offset, limit: effectiveLimit });
|
|
395
|
+
if (handleFileNotFound(result, file)) break;
|
|
166
396
|
if (countMode) {
|
|
167
397
|
console.log(`total: ${result.total}`);
|
|
168
398
|
} else {
|
|
169
|
-
|
|
170
|
-
|
|
399
|
+
const items = result.items || result;
|
|
400
|
+
for (const d of items) console.log(d);
|
|
401
|
+
if (items.length === 0) {
|
|
171
402
|
console.log('(no dependencies)');
|
|
172
|
-
} else if (
|
|
403
|
+
} else if (items.length === effectiveLimit && userLimit === undefined) {
|
|
173
404
|
console.log(`\n(showing top ${effectiveLimit} by relevance — use --limit N or --count for total)`);
|
|
174
405
|
}
|
|
175
406
|
}
|
|
@@ -181,13 +412,15 @@ async function main() {
|
|
|
181
412
|
if (!file) { console.error('Usage: betterrank dependents <file>'); process.exit(1); }
|
|
182
413
|
const effectiveLimit = countMode ? undefined : (userLimit !== undefined ? userLimit : DEFAULT_LIMIT);
|
|
183
414
|
const result = await idx.dependents({ file, count: countMode, offset, limit: effectiveLimit });
|
|
415
|
+
if (handleFileNotFound(result, file)) break;
|
|
184
416
|
if (countMode) {
|
|
185
417
|
console.log(`total: ${result.total}`);
|
|
186
418
|
} else {
|
|
187
|
-
|
|
188
|
-
|
|
419
|
+
const items = result.items || result;
|
|
420
|
+
for (const d of items) console.log(d);
|
|
421
|
+
if (items.length === 0) {
|
|
189
422
|
console.log('(no dependents)');
|
|
190
|
-
} else if (
|
|
423
|
+
} else if (items.length === effectiveLimit && userLimit === undefined) {
|
|
191
424
|
console.log(`\n(showing top ${effectiveLimit} by relevance — use --limit N or --count for total)`);
|
|
192
425
|
}
|
|
193
426
|
}
|
|
@@ -208,6 +441,7 @@ async function main() {
|
|
|
208
441
|
const preview = await idx.neighborhood({
|
|
209
442
|
file, hops, maxFiles: maxFilesFlag, count: true,
|
|
210
443
|
});
|
|
444
|
+
if (handleFileNotFound(preview, file)) break;
|
|
211
445
|
console.log(`files: ${preview.totalFiles} (${preview.totalVisited} visited, ${preview.totalFiles} after ranking)`);
|
|
212
446
|
console.log(`symbols: ${preview.totalSymbols}`);
|
|
213
447
|
console.log(`edges: ${preview.totalEdges}`);
|
|
@@ -219,6 +453,7 @@ async function main() {
|
|
|
219
453
|
file, hops, maxFiles: maxFilesFlag,
|
|
220
454
|
count: countMode, offset, limit: userLimit,
|
|
221
455
|
});
|
|
456
|
+
if (handleFileNotFound(result, file)) break;
|
|
222
457
|
|
|
223
458
|
if (countMode) {
|
|
224
459
|
console.log(`files: ${result.totalFiles} (${result.totalVisited} visited, ${result.totalFiles} after ranking)`);
|
|
@@ -255,6 +490,55 @@ async function main() {
|
|
|
255
490
|
break;
|
|
256
491
|
}
|
|
257
492
|
|
|
493
|
+
case 'orphans': {
|
|
494
|
+
const level = flags.level || 'file';
|
|
495
|
+
if (level !== 'file' && level !== 'symbol') {
|
|
496
|
+
console.error(`Unknown level: "${level}". Use "file" or "symbol".`);
|
|
497
|
+
process.exit(1);
|
|
498
|
+
}
|
|
499
|
+
const effectiveLimit = countMode ? undefined : (userLimit !== undefined ? userLimit : DEFAULT_LIMIT);
|
|
500
|
+
const result = await idx.orphans({ level, kind: flags.kind, count: countMode, offset, limit: effectiveLimit });
|
|
501
|
+
|
|
502
|
+
if (countMode) {
|
|
503
|
+
console.log(`total: ${result.total}`);
|
|
504
|
+
} else if (level === 'file') {
|
|
505
|
+
for (const f of result) {
|
|
506
|
+
console.log(`${f.file} (${f.symbolCount} symbols)`);
|
|
507
|
+
}
|
|
508
|
+
if (result.length === 0) {
|
|
509
|
+
console.log('(no orphan files found)');
|
|
510
|
+
} else {
|
|
511
|
+
const total = await idx.orphans({ level, count: true });
|
|
512
|
+
if (result.length < total.total) {
|
|
513
|
+
console.log(`\nShowing ${result.length} of ${total.total} orphan files (use --limit N for more)`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
} else {
|
|
517
|
+
// symbol level — group by file like map output
|
|
518
|
+
const byFile = new Map();
|
|
519
|
+
for (const s of result) {
|
|
520
|
+
if (!byFile.has(s.file)) byFile.set(s.file, []);
|
|
521
|
+
byFile.get(s.file).push(s);
|
|
522
|
+
}
|
|
523
|
+
for (const [file, syms] of byFile) {
|
|
524
|
+
console.log(`${file}:`);
|
|
525
|
+
for (const s of syms) {
|
|
526
|
+
console.log(` ${String(s.lineStart).padStart(4)}│ [${s.kind}] ${s.signature}`);
|
|
527
|
+
}
|
|
528
|
+
console.log('');
|
|
529
|
+
}
|
|
530
|
+
if (result.length === 0) {
|
|
531
|
+
console.log('(no orphan symbols found)');
|
|
532
|
+
} else {
|
|
533
|
+
const total = await idx.orphans({ level, kind: flags.kind, count: true });
|
|
534
|
+
if (result.length < total.total) {
|
|
535
|
+
console.log(`Showing ${result.length} of ${total.total} orphan symbols across ${byFile.size} files (use --limit N for more)`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
|
|
258
542
|
case 'reindex': {
|
|
259
543
|
const t0 = Date.now();
|
|
260
544
|
const result = await idx.reindex();
|
|
@@ -284,7 +568,10 @@ function parseFlags(args) {
|
|
|
284
568
|
const flags = { _positional: [] };
|
|
285
569
|
let i = 0;
|
|
286
570
|
while (i < args.length) {
|
|
287
|
-
if (args[i]
|
|
571
|
+
if (args[i] === '-h') {
|
|
572
|
+
flags.help = true;
|
|
573
|
+
i++;
|
|
574
|
+
} else if (args[i].startsWith('--')) {
|
|
288
575
|
const key = args[i].substring(2);
|
|
289
576
|
if (i + 1 < args.length && !args[i + 1].startsWith('--')) {
|
|
290
577
|
flags[key] = args[i + 1];
|