@mishasinitcyn/betterrank 0.2.5 → 0.2.6
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/outline.js +63 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mishasinitcyn/betterrank",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
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/outline.js
CHANGED
|
@@ -84,24 +84,79 @@ function expandMode(lines, defs, filePath, expandSymbols, pad) {
|
|
|
84
84
|
return output.join('\n').trimEnd();
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
// Detect a contiguous block of import statements at the top of the file.
|
|
88
|
+
// Returns { start, end, lineCount } (1-indexed) or null if block is < 3 lines.
|
|
89
|
+
// Blank lines and leading non-import lines (e.g. "use client") are skipped over.
|
|
90
|
+
function detectImportBlock(lines) {
|
|
91
|
+
let braceDepth = 0;
|
|
92
|
+
let inImport = false;
|
|
93
|
+
let firstImportLine = -1; // 0-indexed
|
|
94
|
+
let lastImportLine = -1; // 0-indexed
|
|
95
|
+
|
|
96
|
+
for (let i = 0; i < lines.length; i++) {
|
|
97
|
+
const trimmed = lines[i].trim();
|
|
98
|
+
if (trimmed === '') continue;
|
|
99
|
+
|
|
100
|
+
if (!inImport) {
|
|
101
|
+
if (trimmed.startsWith('import ') || trimmed === 'import') {
|
|
102
|
+
if (firstImportLine === -1) firstImportLine = i;
|
|
103
|
+
braceDepth = 0;
|
|
104
|
+
for (const ch of lines[i]) {
|
|
105
|
+
if (ch === '{') braceDepth++;
|
|
106
|
+
else if (ch === '}') braceDepth--;
|
|
107
|
+
}
|
|
108
|
+
if (braceDepth > 0) {
|
|
109
|
+
inImport = true;
|
|
110
|
+
} else {
|
|
111
|
+
lastImportLine = i;
|
|
112
|
+
}
|
|
113
|
+
} else if (firstImportLine !== -1) {
|
|
114
|
+
// First non-blank, non-import line after imports began
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
// else: pre-import line ("use client", comments) — keep scanning
|
|
118
|
+
} else {
|
|
119
|
+
for (const ch of lines[i]) {
|
|
120
|
+
if (ch === '{') braceDepth++;
|
|
121
|
+
else if (ch === '}') braceDepth--;
|
|
122
|
+
}
|
|
123
|
+
if (braceDepth <= 0) {
|
|
124
|
+
inImport = false;
|
|
125
|
+
lastImportLine = i;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (firstImportLine === -1 || lastImportLine === -1) return null;
|
|
131
|
+
const lineCount = lastImportLine - firstImportLine + 1;
|
|
132
|
+
if (lineCount < 3) return null;
|
|
133
|
+
return { start: firstImportLine + 1, end: lastImportLine + 1, lineCount, name: null };
|
|
134
|
+
}
|
|
135
|
+
|
|
87
136
|
function outlineMode(lines, defs, pad, callerCounts) {
|
|
88
|
-
//
|
|
89
|
-
|
|
137
|
+
// Mark definitions that are nested inside another definition.
|
|
138
|
+
// Only top-level defs get their own collapse range — nested ones are swallowed
|
|
139
|
+
// by the parent's collapse, preventing dozens of inline-callback markers.
|
|
140
|
+
const nested = new Set();
|
|
90
141
|
for (const def of defs) {
|
|
91
142
|
for (const other of defs) {
|
|
92
143
|
if (other === def) continue;
|
|
93
|
-
if (
|
|
94
|
-
|
|
144
|
+
if (def.lineStart > other.lineStart && def.lineEnd <= other.lineEnd) {
|
|
145
|
+
nested.add(def);
|
|
95
146
|
break;
|
|
96
147
|
}
|
|
97
148
|
}
|
|
98
149
|
}
|
|
99
150
|
|
|
100
|
-
// Build collapse ranges for leaf definitions with sufficient body size
|
|
101
|
-
// Track which definition each collapse range belongs to (for annotations)
|
|
102
151
|
const collapseRanges = [];
|
|
152
|
+
|
|
153
|
+
// Collapse the import block first (covers the lucide/shadcn import wall in TSX)
|
|
154
|
+
const importCollapse = detectImportBlock(lines);
|
|
155
|
+
if (importCollapse) collapseRanges.push(importCollapse);
|
|
156
|
+
|
|
157
|
+
// Collapse all top-level definitions (functions, classes, interfaces, components)
|
|
103
158
|
for (const def of defs) {
|
|
104
|
-
if (
|
|
159
|
+
if (nested.has(def)) continue;
|
|
105
160
|
if (!def.bodyStartLine) continue;
|
|
106
161
|
if (def.bodyStartLine > def.lineEnd) continue;
|
|
107
162
|
|
|
@@ -131,7 +186,7 @@ function outlineMode(lines, defs, pad, callerCounts) {
|
|
|
131
186
|
let marker = `${' '.repeat(pad)}│ ${indent}... (${range.lineCount} lines)`;
|
|
132
187
|
|
|
133
188
|
// Append caller annotation if available
|
|
134
|
-
if (callerCounts && callerCounts.has(range.name)) {
|
|
189
|
+
if (callerCounts && range.name && callerCounts.has(range.name)) {
|
|
135
190
|
const count = callerCounts.get(range.name);
|
|
136
191
|
const annotation = count === 1 ? '← 1 caller' : `← ${count} callers`;
|
|
137
192
|
// Right-pad to align annotations
|