scip-query 0.3.4 → 0.4.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/README.md +2 -26
- package/dist/{chunk-FYYOWQXK.js → chunk-2F2WH5WQ.js} +19 -36
- package/dist/{chunk-C7H5WBTJ.js → chunk-2UISVZGQ.js} +2 -2
- package/dist/{chunk-HLKAFWWJ.js → chunk-4ZT7UGWW.js} +56 -91
- package/dist/chunk-5AJJGPZE.js +60 -0
- package/dist/chunk-5RKYZSQ6.js +75 -0
- package/dist/chunk-7YBLWIXY.js +115 -0
- package/dist/{chunk-O7Q7FDUJ.js → chunk-A4GWYETB.js} +2 -2
- package/dist/{chunk-CHDJXYBG.js → chunk-A5BGEBM7.js} +2 -2
- package/dist/{chunk-KKCHYLVI.js → chunk-A7YY7IDA.js} +2 -2
- package/dist/chunk-AS7N27JK.js +115 -0
- package/dist/{chunk-F7XU27LU.js → chunk-CQRYLK33.js} +26 -2
- package/dist/{chunk-NFS5W3PP.js → chunk-CQUNEJYM.js} +2 -2
- package/dist/chunk-D4I3ZMN5.js +38 -0
- package/dist/{chunk-J3JSOSUO.js → chunk-E7J7Q7UW.js} +2 -2
- package/dist/{chunk-GEXE2T6I.js → chunk-EOHPASDV.js} +22 -14
- package/dist/chunk-FVH3Y44U.js +1 -0
- package/dist/chunk-GIBETK3W.js +37 -0
- package/dist/{chunk-SMDCNPMK.js → chunk-H3FPW5YN.js} +2 -2
- package/dist/{chunk-GJDHTTR2.js → chunk-HNURMDF4.js} +32 -17
- package/dist/{chunk-7KIMF5PV.js → chunk-HRDPUTIQ.js} +2 -2
- package/dist/{chunk-OIDHN6GD.js → chunk-I2JM34UV.js} +146 -5
- package/dist/{chunk-EPWLXXBL.js → chunk-IV6NZ426.js} +27 -29
- package/dist/{chunk-VT4JBH6L.js → chunk-KDCQJTYW.js} +2 -2
- package/dist/{chunk-5OMVSV6E.js → chunk-LOVDB4C6.js} +2 -2
- package/dist/chunk-MA3B3IUT.js +75 -0
- package/dist/{chunk-26DOJ63W.js → chunk-N2LH3M2P.js} +13 -2
- package/dist/chunk-NWCJWA36.js +162 -0
- package/dist/{chunk-NG5F43OU.js → chunk-P3VCDYMJ.js} +70 -1
- package/dist/{chunk-P3E6L7KW.js → chunk-P42KQKJZ.js} +83 -3
- package/dist/{chunk-YDBXNPYU.js → chunk-PGHN5UTM.js} +2 -2
- package/dist/{chunk-UGQKAVCD.js → chunk-QCYR4S6T.js} +2 -2
- package/dist/chunk-QGCEAVJD.js +2529 -0
- package/dist/{chunk-KBOQX573.js → chunk-RIEA5DOB.js} +19 -2
- package/dist/{chunk-VIYSWZCO.js → chunk-SL674KAW.js} +31 -3
- package/dist/chunk-SRELHCMG.js +110 -0
- package/dist/chunk-UTRKBUCB.js +87 -0
- package/dist/{chunk-HJZUSUPU.js → chunk-VCOJRQPP.js} +5 -5
- package/dist/chunk-VISMEWYP.js +34 -0
- package/dist/{chunk-LFJQVJYJ.js → chunk-VU7FDTWV.js} +2 -2
- package/dist/{chunk-HLUS2HEB.js → chunk-VUBLUTMU.js} +5 -4
- package/dist/{chunk-WGAD3GNR.js → chunk-WNPF2I25.js} +5 -5
- package/dist/{chunk-YY4QGUQ5.js → chunk-X3J4VPWM.js} +2 -2
- package/dist/{chunk-GSH2FPKV.js → chunk-XH56HXLC.js} +2 -2
- package/dist/{chunk-DH7G3DDV.js → chunk-ZU2AQQB5.js} +2 -2
- package/dist/cli.js +2722 -1036
- package/dist/{db-ShvwGDKf.d.ts → db-C4rPbKkI.d.ts} +7 -14
- package/dist/index.d.ts +4 -5
- package/dist/index.js +378 -149
- package/dist/postinstall.js +9 -3
- package/dist/queries/affected.d.ts +1 -1
- package/dist/queries/affected.js +2 -2
- package/dist/queries/bottlenecks.d.ts +1 -1
- package/dist/queries/bottlenecks.js +2 -1
- package/dist/queries/by-kind.d.ts +1 -1
- package/dist/queries/by-kind.js +2 -1
- package/dist/queries/call-graph.d.ts +1 -1
- package/dist/queries/call-graph.js +2 -2
- package/dist/queries/change-surface.d.ts +1 -1
- package/dist/queries/change-surface.js +2 -2
- package/dist/queries/code.d.ts +1 -1
- package/dist/queries/code.js +2 -2
- package/dist/queries/complexity-hotspots.d.ts +1 -1
- package/dist/queries/complexity-hotspots.js +2 -2
- package/dist/queries/complexity.d.ts +1 -1
- package/dist/queries/complexity.js +2 -2
- package/dist/queries/convergence.d.ts +1 -1
- package/dist/queries/convergence.js +2 -2
- package/dist/queries/coupling.d.ts +1 -1
- package/dist/queries/coupling.js +2 -2
- package/dist/queries/cycles.d.ts +1 -1
- package/dist/queries/cycles.js +2 -2
- package/dist/queries/dataflow.d.ts +1 -1
- package/dist/queries/dataflow.js +2 -2
- package/dist/queries/dead.d.ts +1 -1
- package/dist/queries/dead.js +3 -3
- package/dist/queries/deep-chains.d.ts +1 -1
- package/dist/queries/deep-chains.js +2 -2
- package/dist/queries/deps.d.ts +1 -1
- package/dist/queries/deps.js +2 -2
- package/dist/queries/diff-impact.d.ts +1 -1
- package/dist/queries/drift.d.ts +1 -1
- package/dist/queries/drift.js +2 -2
- package/dist/queries/extract-candidates.d.ts +1 -1
- package/dist/queries/extract-candidates.js +2 -2
- package/dist/queries/fan.d.ts +1 -1
- package/dist/queries/fan.js +2 -2
- package/dist/queries/files.d.ts +1 -1
- package/dist/queries/health.d.ts +1 -1
- package/dist/queries/health.js +13 -13
- package/dist/queries/hierarchy.d.ts +1 -1
- package/dist/queries/hierarchy.js +2 -2
- package/dist/queries/hotspots.d.ts +1 -1
- package/dist/queries/hotspots.js +2 -1
- package/dist/queries/imports.d.ts +1 -1
- package/dist/queries/imports.js +2 -2
- package/dist/queries/index.d.ts +1 -2
- package/dist/queries/index.js +49 -53
- package/dist/queries/isolated.d.ts +3 -4
- package/dist/queries/isolated.js +3 -3
- package/dist/queries/members.d.ts +1 -1
- package/dist/queries/members.js +2 -2
- package/dist/queries/methods.d.ts +1 -1
- package/dist/queries/methods.js +2 -1
- package/dist/queries/outline.d.ts +1 -1
- package/dist/queries/outline.js +2 -2
- package/dist/queries/passthrough-candidates.d.ts +1 -1
- package/dist/queries/passthrough-candidates.js +2 -2
- package/dist/queries/redundant-reexports.d.ts +1 -1
- package/dist/queries/redundant-reexports.js +3 -3
- package/dist/queries/refs.d.ts +1 -1
- package/dist/queries/refs.js +2 -2
- package/dist/queries/similar-chains.d.ts +1 -1
- package/dist/queries/similar-chains.js +2 -2
- package/dist/queries/similar-files.d.ts +1 -1
- package/dist/queries/similar-files.js +2 -2
- package/dist/queries/similar-signatures.d.ts +5 -3
- package/dist/queries/similar-signatures.js +2 -1
- package/dist/queries/similar.d.ts +1 -1
- package/dist/queries/similar.js +2 -2
- package/dist/queries/slice.d.ts +1 -1
- package/dist/queries/slice.js +2 -2
- package/dist/queries/stale-abstractions.d.ts +1 -1
- package/dist/queries/stale-abstractions.js +2 -2
- package/dist/queries/stats.d.ts +1 -1
- package/dist/queries/surface.d.ts +1 -1
- package/dist/queries/surface.js +2 -2
- package/dist/queries/symbols.d.ts +1 -1
- package/dist/queries/symbols.js +2 -2
- package/dist/queries/system.d.ts +1 -1
- package/dist/queries/system.js +2 -2
- package/dist/queries/trace.d.ts +1 -1
- package/dist/queries/trace.js +2 -2
- package/dist/queries/wrapper-candidates.d.ts +1 -1
- package/dist/queries/wrapper-candidates.js +2 -2
- package/dist/reindex-worker.js +213 -62
- package/package.json +1 -1
- package/skills/scip-language-playbook/SKILL.md +371 -0
- package/dist/chunk-2UELLEBI.js +0 -1
- package/dist/chunk-4JCSOF2O.js +0 -97
- package/dist/chunk-AXQKUYKF.js +0 -1442
- package/dist/chunk-CPVAQJEC.js +0 -46
- package/dist/chunk-EOROMIFO.js +0 -41
- package/dist/chunk-GU2H5QRN.js +0 -28
- package/dist/chunk-LQJUPXQY.js +0 -109
- package/dist/chunk-MPGIHELS.js +0 -39
- package/dist/chunk-P4WO3BBW.js +0 -64
- package/dist/chunk-TOIEB3LG.js +0 -78
- package/dist/chunk-UQEQ6AHX.js +0 -60
- package/dist/chunk-VJJKSGIX.js +0 -121
- package/dist/chunk-YZ6L7GFO.js +0 -73
- package/dist/chunk-ZEUCXQBN.js +0 -71
- package/dist/queries/doc-coverage.d.ts +0 -14
- package/dist/queries/doc-coverage.js +0 -8
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ For goal-oriented usage guides (not just command reference), see **[Agent Guide]
|
|
|
19
19
|
```bash
|
|
20
20
|
# Install
|
|
21
21
|
npm install -g scip-query
|
|
22
|
+
scip-query install-skills # installs built-in Codex/Claude skills, including scip-language-playbook
|
|
22
23
|
|
|
23
24
|
# Index your project (auto-detects language)
|
|
24
25
|
scip-query reindex
|
|
@@ -487,31 +488,6 @@ scip-query isolated --scope src/utils
|
|
|
487
488
|
|
|
488
489
|
---
|
|
489
490
|
|
|
490
|
-
#### `doc-coverage`
|
|
491
|
-
|
|
492
|
-
Check what percentage of symbols have documentation strings. Lists undocumented symbols.
|
|
493
|
-
|
|
494
|
-
```bash
|
|
495
|
-
scip-query doc-coverage --min-loc 5
|
|
496
|
-
# Documentation coverage: 78%
|
|
497
|
-
# Total symbols: 122
|
|
498
|
-
# Documented: 95
|
|
499
|
-
# Undocumented: 27
|
|
500
|
-
#
|
|
501
|
-
# Undocumented:
|
|
502
|
-
# src/utils/format.ts:15 formatCurrency
|
|
503
|
-
# src/utils/format.ts:28 formatDate
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
**Options:**
|
|
507
|
-
- `-s, --scope <path>` — Limit to files matching path
|
|
508
|
-
- `--min-loc <n>` — Minimum LOC to consider (default: 3)
|
|
509
|
-
- `-n, --limit <n>` — Max undocumented symbols to show (default: 50)
|
|
510
|
-
|
|
511
|
-
**Value:** Documentation health check. Focus efforts on the undocumented list.
|
|
512
|
-
|
|
513
|
-
---
|
|
514
|
-
|
|
515
491
|
### Codebase Metrics
|
|
516
492
|
|
|
517
493
|
These commands measure structural properties of the codebase — hotspots, coupling, bottlenecks, fan-in/out.
|
|
@@ -1148,7 +1124,7 @@ scip-query similar-signatures --min-loc 5
|
|
|
1148
1124
|
|
|
1149
1125
|
## Programmatic API
|
|
1150
1126
|
|
|
1151
|
-
All
|
|
1127
|
+
All 49 commands are available as TypeScript functions:
|
|
1152
1128
|
|
|
1153
1129
|
```typescript
|
|
1154
1130
|
import {
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
staleAbstractions
|
|
3
|
-
} from "./chunk-P4WO3BBW.js";
|
|
4
1
|
import {
|
|
5
2
|
stats
|
|
6
3
|
} from "./chunk-74RFWB5T.js";
|
|
7
4
|
import {
|
|
8
5
|
wrapperCandidates
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import {
|
|
11
|
-
passthroughCandidates
|
|
12
|
-
} from "./chunk-ZEUCXQBN.js";
|
|
6
|
+
} from "./chunk-AS7N27JK.js";
|
|
13
7
|
import {
|
|
14
8
|
similarAll
|
|
15
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-I2JM34UV.js";
|
|
10
|
+
import {
|
|
11
|
+
staleAbstractions
|
|
12
|
+
} from "./chunk-5RKYZSQ6.js";
|
|
16
13
|
import {
|
|
17
14
|
isolated
|
|
18
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-VISMEWYP.js";
|
|
16
|
+
import {
|
|
17
|
+
passthroughCandidates
|
|
18
|
+
} from "./chunk-5AJJGPZE.js";
|
|
19
19
|
import {
|
|
20
20
|
drift
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-HRDPUTIQ.js";
|
|
22
22
|
import {
|
|
23
23
|
extractCandidates
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-IV6NZ426.js";
|
|
25
25
|
import {
|
|
26
26
|
complexityHotspots
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-SL674KAW.js";
|
|
28
28
|
import {
|
|
29
29
|
cycles
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-VU7FDTWV.js";
|
|
31
31
|
import {
|
|
32
32
|
dead
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-SRELHCMG.js";
|
|
34
34
|
import {
|
|
35
35
|
isEntrySurface
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-X3J4VPWM.js";
|
|
37
37
|
|
|
38
38
|
// src/queries/health.ts
|
|
39
39
|
function health(db, opts = {}) {
|
|
@@ -57,20 +57,7 @@ function health(db, opts = {}) {
|
|
|
57
57
|
const trueIsolatedCount = isolatedResult.filter(
|
|
58
58
|
(s2) => !isEntrySurface(db, s2.relativePath)
|
|
59
59
|
).length;
|
|
60
|
-
const
|
|
61
|
-
db.all(
|
|
62
|
-
`SELECT DISTINCT d.relative_path
|
|
63
|
-
FROM global_symbols gs
|
|
64
|
-
JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
|
|
65
|
-
JOIN documents d ON der.document_id = d.id
|
|
66
|
-
WHERE gs.symbol LIKE '%().'
|
|
67
|
-
${db.pathExclusionsFor("d")}`
|
|
68
|
-
).map((r) => r.relative_path)
|
|
69
|
-
);
|
|
70
|
-
const trueStaleCount = staleResult.filter((s2) => {
|
|
71
|
-
if (s2.consumers === 0 && filesWithFunctions.has(s2.file)) return false;
|
|
72
|
-
return true;
|
|
73
|
-
}).length;
|
|
60
|
+
const trueStaleCount = staleResult.length;
|
|
74
61
|
const trueDriftCount = driftResult.results.length;
|
|
75
62
|
const trueSimilarCount = similarResult.length;
|
|
76
63
|
const actions = [];
|
|
@@ -145,11 +132,7 @@ function health(db, opts = {}) {
|
|
|
145
132
|
});
|
|
146
133
|
}
|
|
147
134
|
if (trueStaleCount > 0) {
|
|
148
|
-
const
|
|
149
|
-
if (s2.consumers === 0 && filesWithFunctions.has(s2.file)) return false;
|
|
150
|
-
return true;
|
|
151
|
-
});
|
|
152
|
-
const unused = trueStaleSymbols.filter((s2) => s2.consumers === 0).length;
|
|
135
|
+
const unused = staleResult.filter((s2) => s2.consumers === 0).length;
|
|
153
136
|
const singleUse = trueStaleCount - unused;
|
|
154
137
|
const parts = [];
|
|
155
138
|
if (unused > 0) parts.push(`${unused} unused`);
|
|
@@ -160,7 +143,7 @@ function health(db, opts = {}) {
|
|
|
160
143
|
effort: "low",
|
|
161
144
|
impact: "medium",
|
|
162
145
|
count: trueStaleCount,
|
|
163
|
-
locRecoverable: staleResult.
|
|
146
|
+
locRecoverable: staleResult.reduce((sum, r) => sum + r.loc, 0)
|
|
164
147
|
});
|
|
165
148
|
}
|
|
166
149
|
if (trueDriftCount > 0) {
|
|
@@ -235,4 +218,4 @@ function health(db, opts = {}) {
|
|
|
235
218
|
export {
|
|
236
219
|
health
|
|
237
220
|
};
|
|
238
|
-
//# sourceMappingURL=chunk-
|
|
221
|
+
//# sourceMappingURL=chunk-2F2WH5WQ.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
findFirstSymbolMatch,
|
|
3
3
|
getCalleeRowsForSymbol,
|
|
4
4
|
getCallerRowsForSymbol
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-QGCEAVJD.js";
|
|
6
6
|
import {
|
|
7
7
|
shortenSymbol
|
|
8
8
|
} from "./chunk-QIXNAB5K.js";
|
|
@@ -43,4 +43,4 @@ function uniqueRows(rows) {
|
|
|
43
43
|
export {
|
|
44
44
|
callGraph
|
|
45
45
|
};
|
|
46
|
-
//# sourceMappingURL=chunk-
|
|
46
|
+
//# sourceMappingURL=chunk-2UISVZGQ.js.map
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAllDefinitions
|
|
3
|
+
} from "./chunk-QGCEAVJD.js";
|
|
1
4
|
import {
|
|
2
5
|
leafSuffix,
|
|
3
6
|
parseSymbol,
|
|
@@ -115,102 +118,26 @@ function byKind(db, kindQuery, opts = {}) {
|
|
|
115
118
|
if (kindNum === null) {
|
|
116
119
|
return [];
|
|
117
120
|
}
|
|
118
|
-
const
|
|
119
|
-
const hasKinds = db.get(
|
|
120
|
-
`SELECT COUNT(*) AS c FROM global_symbols WHERE kind IS NOT NULL`
|
|
121
|
-
);
|
|
122
|
-
if (!hasKinds || hasKinds.c === 0) {
|
|
123
|
-
return inferByKind(db, kindNum, scope, limit);
|
|
124
|
-
}
|
|
125
|
-
const rows = db.all(
|
|
126
|
-
`SELECT gs.symbol, gs.kind, d.relative_path, der.start_line, der.end_line
|
|
127
|
-
FROM global_symbols gs
|
|
128
|
-
JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
|
|
129
|
-
JOIN documents d ON der.document_id = d.id
|
|
130
|
-
WHERE gs.kind = ?
|
|
131
|
-
${db.pathExclusionsFor("d")}
|
|
132
|
-
${scopeFilter}
|
|
133
|
-
ORDER BY d.relative_path, der.start_line
|
|
134
|
-
LIMIT ?`,
|
|
135
|
-
kindNum,
|
|
136
|
-
limit
|
|
137
|
-
);
|
|
138
|
-
return rows.filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({
|
|
139
|
-
symbol: r.symbol,
|
|
140
|
-
shortName: shortenSymbol(r.symbol),
|
|
141
|
-
kind: r.kind,
|
|
142
|
-
kindName: KIND_NAMES[r.kind] ?? "Unknown",
|
|
143
|
-
relativePath: r.relative_path,
|
|
144
|
-
startLine: r.start_line,
|
|
145
|
-
endLine: r.end_line
|
|
146
|
-
}));
|
|
147
|
-
}
|
|
148
|
-
function kindCounts(db, opts = {}) {
|
|
149
|
-
const scopeFilter = opts.scope ? `AND d.relative_path LIKE '%${opts.scope}%'` : "";
|
|
150
|
-
const rows = db.all(
|
|
151
|
-
`SELECT gs.kind, COUNT(*) AS cnt
|
|
152
|
-
FROM global_symbols gs
|
|
153
|
-
JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
|
|
154
|
-
JOIN documents d ON der.document_id = d.id
|
|
155
|
-
WHERE 1 = 1
|
|
156
|
-
${db.pathExclusionsFor("d")}
|
|
157
|
-
AND gs.kind IS NOT NULL
|
|
158
|
-
AND gs.kind != 0
|
|
159
|
-
${scopeFilter}
|
|
160
|
-
GROUP BY gs.kind
|
|
161
|
-
ORDER BY cnt DESC`
|
|
162
|
-
);
|
|
163
|
-
if (rows.length === 0) {
|
|
164
|
-
return inferKindCounts(db, opts.scope);
|
|
165
|
-
}
|
|
166
|
-
return rows.map((r) => ({
|
|
167
|
-
kind: r.kind,
|
|
168
|
-
kindName: KIND_NAMES[r.kind] ?? "Unknown",
|
|
169
|
-
count: r.cnt
|
|
170
|
-
}));
|
|
171
|
-
}
|
|
172
|
-
function inferByKind(db, kindNum, scope, limit = 100) {
|
|
173
|
-
const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
|
|
174
|
-
const rows = db.all(
|
|
175
|
-
`SELECT gs.symbol, d.relative_path, der.start_line, der.end_line, gs.documentation, gs.enclosing_symbol
|
|
176
|
-
FROM global_symbols gs
|
|
177
|
-
JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
|
|
178
|
-
JOIN documents d ON der.document_id = d.id
|
|
179
|
-
WHERE 1 = 1
|
|
180
|
-
${db.pathExclusionsFor("d")}
|
|
181
|
-
${scopeFilter}
|
|
182
|
-
ORDER BY d.relative_path, der.start_line`
|
|
183
|
-
);
|
|
184
|
-
return rows.filter((row) => !db.isIgnored(row.relative_path)).map((row) => ({
|
|
121
|
+
const rows = loadKindRows(db, scope).map((row) => ({
|
|
185
122
|
row,
|
|
186
|
-
|
|
187
|
-
})).filter((entry) => entry.
|
|
123
|
+
resolvedKind: resolveKindNumber(row)
|
|
124
|
+
})).filter((entry) => entry.resolvedKind === kindNum).slice(0, limit);
|
|
125
|
+
return rows.map(({ row, resolvedKind }) => ({
|
|
188
126
|
symbol: row.symbol,
|
|
189
127
|
shortName: shortenSymbol(row.symbol),
|
|
190
|
-
kind:
|
|
191
|
-
kindName: KIND_NAMES[
|
|
128
|
+
kind: resolvedKind,
|
|
129
|
+
kindName: KIND_NAMES[resolvedKind] ?? "Unknown",
|
|
192
130
|
relativePath: row.relative_path,
|
|
193
131
|
startLine: row.start_line,
|
|
194
132
|
endLine: row.end_line
|
|
195
133
|
}));
|
|
196
134
|
}
|
|
197
|
-
function
|
|
198
|
-
const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
|
|
199
|
-
const rows = db.all(
|
|
200
|
-
`SELECT gs.symbol, gs.documentation, gs.enclosing_symbol, d.relative_path
|
|
201
|
-
FROM global_symbols gs
|
|
202
|
-
JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
|
|
203
|
-
JOIN documents d ON der.document_id = d.id
|
|
204
|
-
WHERE 1 = 1
|
|
205
|
-
${db.pathExclusionsFor("d")}
|
|
206
|
-
${scopeFilter}`
|
|
207
|
-
);
|
|
135
|
+
function kindCounts(db, opts = {}) {
|
|
208
136
|
const counts = /* @__PURE__ */ new Map();
|
|
209
|
-
for (const row of
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
counts.set(inferred, (counts.get(inferred) ?? 0) + 1);
|
|
137
|
+
for (const row of loadKindRows(db, opts.scope)) {
|
|
138
|
+
const kind = resolveKindNumber(row);
|
|
139
|
+
if (kind === null || kind === 0) continue;
|
|
140
|
+
counts.set(kind, (counts.get(kind) ?? 0) + 1);
|
|
214
141
|
}
|
|
215
142
|
return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0] - b[0]).map(([kind, count]) => ({
|
|
216
143
|
kind,
|
|
@@ -218,22 +145,60 @@ function inferKindCounts(db, scope) {
|
|
|
218
145
|
count
|
|
219
146
|
}));
|
|
220
147
|
}
|
|
148
|
+
function loadKindRows(db, scope) {
|
|
149
|
+
return getAllDefinitions(db, { scope }).map(mapDefinitionToKindRow);
|
|
150
|
+
}
|
|
151
|
+
function mapDefinitionToKindRow(definition) {
|
|
152
|
+
return {
|
|
153
|
+
symbol: definition.symbol,
|
|
154
|
+
kind: definition.kind,
|
|
155
|
+
documentation: definition.documentation,
|
|
156
|
+
enclosing_symbol: definition.enclosingSymbol,
|
|
157
|
+
relative_path: definition.relativePath,
|
|
158
|
+
start_line: definition.startLine,
|
|
159
|
+
end_line: definition.endLine
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function resolveKindNumber(row) {
|
|
163
|
+
if (row.kind !== null && row.kind !== 0) {
|
|
164
|
+
return normalizeIndexedKind(row.kind, row.symbol, row.documentation);
|
|
165
|
+
}
|
|
166
|
+
return inferKindNumber(row.symbol, row.documentation, row.enclosing_symbol);
|
|
167
|
+
}
|
|
168
|
+
function normalizeIndexedKind(kind, symbol, documentation) {
|
|
169
|
+
const signature = (documentation ?? "").toLowerCase();
|
|
170
|
+
const suffix = leafSuffix(symbol);
|
|
171
|
+
if (suffix === "type") {
|
|
172
|
+
if (signature.includes("type ")) return 76;
|
|
173
|
+
if (signature.includes("interface ")) return 27;
|
|
174
|
+
if (signature.includes("struct ")) return 68;
|
|
175
|
+
if (signature.includes("trait ")) return 73;
|
|
176
|
+
if (signature.includes("class ")) return 9;
|
|
177
|
+
}
|
|
178
|
+
return kind;
|
|
179
|
+
}
|
|
221
180
|
function inferKindNumber(symbol, documentation, enclosingSymbol) {
|
|
222
181
|
const parsed = parseSymbol(symbol);
|
|
223
182
|
if ("kind" in parsed) {
|
|
224
183
|
return null;
|
|
225
184
|
}
|
|
226
185
|
const descriptors = parsed.descriptors;
|
|
227
|
-
const last = descriptors[descriptors.length - 1] ?? null;
|
|
228
186
|
const parent = descriptors[descriptors.length - 2] ?? null;
|
|
229
187
|
const suffix = leafSuffix(symbol);
|
|
230
|
-
|
|
188
|
+
const signature = (documentation ?? "").toLowerCase();
|
|
189
|
+
if (suffix === "type") {
|
|
190
|
+
if (signature.includes("type ")) return 76;
|
|
191
|
+
if (signature.includes("interface ")) return 27;
|
|
192
|
+
if (signature.includes("struct ")) return 68;
|
|
193
|
+
if (signature.includes("trait ")) return 73;
|
|
194
|
+
if (signature.includes("class ")) return 9;
|
|
195
|
+
return 9;
|
|
196
|
+
}
|
|
231
197
|
if (suffix === "method") {
|
|
232
198
|
return parent?.suffix === "type" ? 33 : 23;
|
|
233
199
|
}
|
|
234
200
|
if (suffix === "namespace") return 39;
|
|
235
201
|
if (suffix !== "term") return null;
|
|
236
|
-
const signature = (documentation ?? "").toLowerCase();
|
|
237
202
|
if (signature.includes("async def ") || signature.includes("def ")) {
|
|
238
203
|
return 23;
|
|
239
204
|
}
|
|
@@ -248,4 +213,4 @@ export {
|
|
|
248
213
|
byKind,
|
|
249
214
|
kindCounts
|
|
250
215
|
};
|
|
251
|
-
//# sourceMappingURL=chunk-
|
|
216
|
+
//# sourceMappingURL=chunk-4ZT7UGWW.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCalleeRowsForSymbol,
|
|
3
|
+
getDefinitionsForFile
|
|
4
|
+
} from "./chunk-QGCEAVJD.js";
|
|
5
|
+
import {
|
|
6
|
+
isFunctionLikeSymbol,
|
|
7
|
+
shortenSymbol
|
|
8
|
+
} from "./chunk-QIXNAB5K.js";
|
|
9
|
+
|
|
10
|
+
// src/queries/passthrough-candidates.ts
|
|
11
|
+
function passthroughCandidates(db, opts) {
|
|
12
|
+
const { scope, maxLoc = 15, limit = 30 } = opts ?? {};
|
|
13
|
+
const symbols = getScopedDefinitions(db, scope).filter((definition) => definitionLoc(definition) >= 3 && definitionLoc(definition) <= maxLoc);
|
|
14
|
+
const results = [];
|
|
15
|
+
for (const sym of symbols) {
|
|
16
|
+
if (db.isIgnored(sym.relativePath) || !isFunctionLikeSymbol(sym.symbol)) continue;
|
|
17
|
+
const rawCallees = getCalleeRowsForSymbol(db, sym);
|
|
18
|
+
const callees = rawCallees.some((callee2) => isFunctionLikeSymbol(callee2.symbol)) ? rawCallees.filter((callee2) => isFunctionLikeSymbol(callee2.symbol)) : rawCallees;
|
|
19
|
+
const uniqueCallees = /* @__PURE__ */ new Map();
|
|
20
|
+
for (const c of callees) {
|
|
21
|
+
if (!uniqueCallees.has(c.symbol)) {
|
|
22
|
+
uniqueCallees.set(c.symbol, { symbol: c.symbol, file: c.file });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (uniqueCallees.size !== 1) continue;
|
|
26
|
+
const [, callee] = [...uniqueCallees.entries()][0];
|
|
27
|
+
results.push({
|
|
28
|
+
symbol: sym.symbol,
|
|
29
|
+
shortName: shortenSymbol(sym.symbol),
|
|
30
|
+
file: sym.relativePath,
|
|
31
|
+
startLine: sym.startLine,
|
|
32
|
+
endLine: sym.endLine,
|
|
33
|
+
loc: definitionLoc(sym),
|
|
34
|
+
forwardsTo: callee.symbol,
|
|
35
|
+
forwardsToShort: shortenSymbol(callee.symbol),
|
|
36
|
+
forwardsToFile: callee.file
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
results.sort((a, b) => a.loc - b.loc || a.file.localeCompare(b.file));
|
|
40
|
+
return results.slice(0, limit);
|
|
41
|
+
}
|
|
42
|
+
function getScopedDefinitions(db, scope) {
|
|
43
|
+
const scopeFilter = scope ? `AND relative_path LIKE '%${scope}%'` : "";
|
|
44
|
+
return db.all(
|
|
45
|
+
`SELECT relative_path
|
|
46
|
+
FROM documents
|
|
47
|
+
WHERE 1 = 1
|
|
48
|
+
${db.pathExclusionsFor("documents")}
|
|
49
|
+
${scopeFilter}
|
|
50
|
+
ORDER BY relative_path`
|
|
51
|
+
).flatMap((row) => getDefinitionsForFile(db, row.relative_path)).filter((row) => !db.isIgnored(row.relativePath));
|
|
52
|
+
}
|
|
53
|
+
function definitionLoc(definition) {
|
|
54
|
+
return definition.endLine - definition.startLine + 1;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
passthroughCandidates
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=chunk-5AJJGPZE.js.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getDefinitionsForFile
|
|
3
|
+
} from "./chunk-QGCEAVJD.js";
|
|
4
|
+
import {
|
|
5
|
+
shortenSymbol
|
|
6
|
+
} from "./chunk-QIXNAB5K.js";
|
|
7
|
+
|
|
8
|
+
// src/queries/stale-abstractions.ts
|
|
9
|
+
function staleAbstractions(db, opts) {
|
|
10
|
+
const { scope, minLoc = 3, limit = 30 } = opts ?? {};
|
|
11
|
+
const rows = getScopedDefinitions(db, scope).filter((definition) => definition.isTypeLike && definitionLoc(definition) >= minLoc).map((definition) => ({
|
|
12
|
+
symbol: definition.symbol,
|
|
13
|
+
file: definition.relativePath,
|
|
14
|
+
start_line: definition.startLine,
|
|
15
|
+
end_line: definition.endLine,
|
|
16
|
+
loc: definitionLoc(definition),
|
|
17
|
+
consumers: countCrossFileConsumers(db, definition)
|
|
18
|
+
})).filter((row) => row.consumers <= 1).sort((left, right) => right.loc - left.loc || left.file.localeCompare(right.file) || left.start_line - right.start_line);
|
|
19
|
+
const filesWithFunctions = getFilesWithFunctions(db, scope);
|
|
20
|
+
return rows.filter((r) => !db.isIgnored(r.file)).filter((r) => isTrueStaleAbstraction(r, filesWithFunctions)).map((r) => ({
|
|
21
|
+
symbol: r.symbol,
|
|
22
|
+
shortName: shortenSymbol(r.symbol),
|
|
23
|
+
file: r.file,
|
|
24
|
+
startLine: r.start_line,
|
|
25
|
+
endLine: r.end_line,
|
|
26
|
+
loc: r.loc,
|
|
27
|
+
consumers: r.consumers
|
|
28
|
+
})).slice(0, limit);
|
|
29
|
+
}
|
|
30
|
+
function getFilesWithFunctions(db, scope) {
|
|
31
|
+
return new Set(getScopedDefinitions(db, scope).filter((definition) => definition.isFunctionLike).map((definition) => definition.relativePath));
|
|
32
|
+
}
|
|
33
|
+
function isTrueStaleAbstraction(row, filesWithFunctions) {
|
|
34
|
+
const basename = row.file.split("/").pop() ?? "";
|
|
35
|
+
const isTypeFile = basename.includes("types") || row.file.includes("/types/");
|
|
36
|
+
if (isTypeFile && row.consumers > 0) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
if (row.consumers === 0 && filesWithFunctions.has(row.file)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
function getScopedDefinitions(db, scope) {
|
|
45
|
+
const scopeFilter = scope ? `AND relative_path LIKE '%${scope}%'` : "";
|
|
46
|
+
return db.all(
|
|
47
|
+
`SELECT relative_path
|
|
48
|
+
FROM documents
|
|
49
|
+
WHERE 1 = 1
|
|
50
|
+
${db.pathExclusionsFor("documents")}
|
|
51
|
+
${scopeFilter}
|
|
52
|
+
ORDER BY relative_path`
|
|
53
|
+
).flatMap((row) => getDefinitionsForFile(db, row.relative_path)).filter((row) => !db.isIgnored(row.relativePath));
|
|
54
|
+
}
|
|
55
|
+
function countCrossFileConsumers(db, definition) {
|
|
56
|
+
const callers = db.all(
|
|
57
|
+
`SELECT DISTINCT d.relative_path
|
|
58
|
+
FROM mentions m
|
|
59
|
+
JOIN chunks c ON m.chunk_id = c.id
|
|
60
|
+
JOIN documents d ON c.document_id = d.id
|
|
61
|
+
WHERE m.symbol_id = ?
|
|
62
|
+
AND m.role != 1
|
|
63
|
+
${db.pathExclusionsFor("d")}`,
|
|
64
|
+
definition.symbolId
|
|
65
|
+
).map((row) => row.relative_path).filter((relativePath) => relativePath !== definition.relativePath && !db.isIgnored(relativePath));
|
|
66
|
+
return new Set(callers).size;
|
|
67
|
+
}
|
|
68
|
+
function definitionLoc(definition) {
|
|
69
|
+
return definition.endLine - definition.startLine + 1;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
staleAbstractions
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=chunk-5RKYZSQ6.js.map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findFirstSymbolMatch,
|
|
3
|
+
getSourceReferenceSites,
|
|
4
|
+
getSourceText
|
|
5
|
+
} from "./chunk-QGCEAVJD.js";
|
|
6
|
+
import {
|
|
7
|
+
isFunctionLikeSymbol
|
|
8
|
+
} from "./chunk-QIXNAB5K.js";
|
|
9
|
+
|
|
10
|
+
// src/queries/refs.ts
|
|
11
|
+
function refs(db, symbolPattern) {
|
|
12
|
+
const match = findFirstSymbolMatch(db, symbolPattern);
|
|
13
|
+
if (match) {
|
|
14
|
+
const includeDefinitionSite = !isFunctionLikeSymbol(match.symbol);
|
|
15
|
+
const definitionRows = includeDefinitionSite ? [{
|
|
16
|
+
relativePath: match.relativePath,
|
|
17
|
+
line: match.startLine
|
|
18
|
+
}] : [];
|
|
19
|
+
const sourceSites = getSourceReferenceSites(db, match).filter((site) => !db.isIgnored(site.file)).map((site) => ({
|
|
20
|
+
relativePath: site.file,
|
|
21
|
+
line: site.line
|
|
22
|
+
}));
|
|
23
|
+
if (sourceSites.length > 0) {
|
|
24
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
25
|
+
const rows2 = [...definitionRows, ...sourceSites, ...getRubySemanticRefs(db, match)].filter((site) => {
|
|
26
|
+
const key = `${site.relativePath}:${site.line}`;
|
|
27
|
+
if (seen2.has(key)) return false;
|
|
28
|
+
seen2.add(key);
|
|
29
|
+
return true;
|
|
30
|
+
});
|
|
31
|
+
return rows2;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const rows = db.all(
|
|
35
|
+
`SELECT DISTINCT d.relative_path, c.start_line
|
|
36
|
+
FROM mentions m
|
|
37
|
+
JOIN chunks c ON m.chunk_id = c.id
|
|
38
|
+
JOIN documents d ON c.document_id = d.id
|
|
39
|
+
JOIN global_symbols gs ON m.symbol_id = gs.id
|
|
40
|
+
WHERE m.symbol_id = ?
|
|
41
|
+
AND ${db.localSymbolPredicate}
|
|
42
|
+
AND m.role != 1
|
|
43
|
+
ORDER BY d.relative_path, c.start_line`,
|
|
44
|
+
match?.symbolId ?? -1
|
|
45
|
+
);
|
|
46
|
+
const referenceRows = rows.filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({
|
|
47
|
+
relativePath: r.relative_path,
|
|
48
|
+
line: r.start_line
|
|
49
|
+
}));
|
|
50
|
+
if (!match || db.isIgnored(match.relativePath) || isFunctionLikeSymbol(match.symbol)) {
|
|
51
|
+
return referenceRows;
|
|
52
|
+
}
|
|
53
|
+
const seen = new Set(referenceRows.map((row) => `${row.relativePath}:${row.line}`));
|
|
54
|
+
if (!seen.has(`${match.relativePath}:${match.startLine}`)) {
|
|
55
|
+
referenceRows.unshift({
|
|
56
|
+
relativePath: match.relativePath,
|
|
57
|
+
line: match.startLine
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
for (const row of getRubySemanticRefs(db, match)) {
|
|
61
|
+
const key = `${row.relativePath}:${row.line}`;
|
|
62
|
+
if (seen.has(key)) continue;
|
|
63
|
+
seen.add(key);
|
|
64
|
+
referenceRows.push(row);
|
|
65
|
+
}
|
|
66
|
+
return referenceRows;
|
|
67
|
+
}
|
|
68
|
+
function getRubySemanticRefs(db, match) {
|
|
69
|
+
if (!match.relativePath.endsWith(".rb")) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
const tokens = rubyReferenceTokens(match.symbol);
|
|
73
|
+
if (tokens.length === 0) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
const rows = db.all(
|
|
77
|
+
`SELECT relative_path
|
|
78
|
+
FROM documents
|
|
79
|
+
WHERE relative_path LIKE '%.rb'
|
|
80
|
+
${db.pathExclusionsFor("documents")}
|
|
81
|
+
ORDER BY relative_path`
|
|
82
|
+
);
|
|
83
|
+
const results = [];
|
|
84
|
+
for (const row of rows) {
|
|
85
|
+
if (db.isIgnored(row.relative_path)) continue;
|
|
86
|
+
const source = getSourceText(db, row.relative_path);
|
|
87
|
+
if (!source) continue;
|
|
88
|
+
const lines = source.split("\n");
|
|
89
|
+
for (let index = 0; index < lines.length; index++) {
|
|
90
|
+
const line = lines[index] ?? "";
|
|
91
|
+
if (tokens.some((token) => new RegExp(`@${token}\\b|\\b${token}:`).test(line))) {
|
|
92
|
+
results.push({
|
|
93
|
+
relativePath: row.relative_path,
|
|
94
|
+
line: index
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return results;
|
|
100
|
+
}
|
|
101
|
+
function rubyReferenceTokens(rawSymbol) {
|
|
102
|
+
const leaf = rawSymbol.split(":").pop() ?? rawSymbol;
|
|
103
|
+
const snake = leaf.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9_]+/g, "_").toLowerCase().replace(/^_+|_+$/g, "");
|
|
104
|
+
const parts = snake.split("_").filter(Boolean);
|
|
105
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
106
|
+
if (snake) candidates.add(snake);
|
|
107
|
+
if (parts.length >= 1) candidates.add(parts[parts.length - 1]);
|
|
108
|
+
if (parts.length >= 2) candidates.add(parts.slice(-2).join("_"));
|
|
109
|
+
return [...candidates];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export {
|
|
113
|
+
refs
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=chunk-7YBLWIXY.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-4TYLS5XX.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveIndexedPaths
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QGCEAVJD.js";
|
|
7
7
|
import {
|
|
8
8
|
shortenSymbol
|
|
9
9
|
} from "./chunk-QIXNAB5K.js";
|
|
@@ -79,4 +79,4 @@ function system(db, modulePattern) {
|
|
|
79
79
|
export {
|
|
80
80
|
system
|
|
81
81
|
};
|
|
82
|
-
//# sourceMappingURL=chunk-
|
|
82
|
+
//# sourceMappingURL=chunk-A4GWYETB.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
findFirstSymbolMatch,
|
|
3
3
|
getCalleeRowsForSymbol
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QGCEAVJD.js";
|
|
5
5
|
import {
|
|
6
6
|
shortenSymbol
|
|
7
7
|
} from "./chunk-QIXNAB5K.js";
|
|
@@ -97,4 +97,4 @@ function forwardSlice(db, match) {
|
|
|
97
97
|
export {
|
|
98
98
|
slice
|
|
99
99
|
};
|
|
100
|
-
//# sourceMappingURL=chunk-
|
|
100
|
+
//# sourceMappingURL=chunk-A5BGEBM7.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveIndexedFile
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QGCEAVJD.js";
|
|
4
4
|
|
|
5
5
|
// src/queries/coupling.ts
|
|
6
6
|
function coupling(db, file1, file2) {
|
|
@@ -81,4 +81,4 @@ export {
|
|
|
81
81
|
coupling,
|
|
82
82
|
topCoupling
|
|
83
83
|
};
|
|
84
|
-
//# sourceMappingURL=chunk-
|
|
84
|
+
//# sourceMappingURL=chunk-A7YY7IDA.js.map
|