scip-query 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/IMPROVEMENTS.md +143 -0
- package/PLAN.md +320 -0
- package/README.md +1213 -0
- package/dist/chunk-2QZ23IBN.js +55 -0
- package/dist/chunk-2QZ23IBN.js.map +1 -0
- package/dist/chunk-36OMT7ZJ.js +144 -0
- package/dist/chunk-36OMT7ZJ.js.map +1 -0
- package/dist/chunk-3E2X7RIE.js +101 -0
- package/dist/chunk-3E2X7RIE.js.map +1 -0
- package/dist/chunk-3UOUTZQT.js +45 -0
- package/dist/chunk-3UOUTZQT.js.map +1 -0
- package/dist/chunk-3ZZJVBIO.js +88 -0
- package/dist/chunk-3ZZJVBIO.js.map +1 -0
- package/dist/chunk-4TYLS5XX.js +10 -0
- package/dist/chunk-4TYLS5XX.js.map +1 -0
- package/dist/chunk-5FGUEU7N.js +101 -0
- package/dist/chunk-5FGUEU7N.js.map +1 -0
- package/dist/chunk-5WTJAXY2.js +61 -0
- package/dist/chunk-5WTJAXY2.js.map +1 -0
- package/dist/chunk-6NBLIDF4.js +24 -0
- package/dist/chunk-6NBLIDF4.js.map +1 -0
- package/dist/chunk-6SXADWLW.js +43 -0
- package/dist/chunk-6SXADWLW.js.map +1 -0
- package/dist/chunk-6VJ6Q7IE.js +65 -0
- package/dist/chunk-6VJ6Q7IE.js.map +1 -0
- package/dist/chunk-7OZPA5OO.js +258 -0
- package/dist/chunk-7OZPA5OO.js.map +1 -0
- package/dist/chunk-BEPIEVLR.js +76 -0
- package/dist/chunk-BEPIEVLR.js.map +1 -0
- package/dist/chunk-BFSCMC22.js +42 -0
- package/dist/chunk-BFSCMC22.js.map +1 -0
- package/dist/chunk-BP2ATLK2.js +110 -0
- package/dist/chunk-BP2ATLK2.js.map +1 -0
- package/dist/chunk-CM454WL3.js +114 -0
- package/dist/chunk-CM454WL3.js.map +1 -0
- package/dist/chunk-DCKMSTJ4.js +74 -0
- package/dist/chunk-DCKMSTJ4.js.map +1 -0
- package/dist/chunk-DEZKCZXD.js +40 -0
- package/dist/chunk-DEZKCZXD.js.map +1 -0
- package/dist/chunk-DVWGWHFW.js +99 -0
- package/dist/chunk-DVWGWHFW.js.map +1 -0
- package/dist/chunk-EMDQWNYR.js +102 -0
- package/dist/chunk-EMDQWNYR.js.map +1 -0
- package/dist/chunk-FFSWWE5O.js +33 -0
- package/dist/chunk-FFSWWE5O.js.map +1 -0
- package/dist/chunk-FGXRVW7G.js +73 -0
- package/dist/chunk-FGXRVW7G.js.map +1 -0
- package/dist/chunk-FUHJCHS4.js +158 -0
- package/dist/chunk-FUHJCHS4.js.map +1 -0
- package/dist/chunk-GJFURBEW.js +64 -0
- package/dist/chunk-GJFURBEW.js.map +1 -0
- package/dist/chunk-GTILYBH6.js +102 -0
- package/dist/chunk-GTILYBH6.js.map +1 -0
- package/dist/chunk-JJP7KQND.js +1 -0
- package/dist/chunk-JJP7KQND.js.map +1 -0
- package/dist/chunk-JKP5GH6T.js +213 -0
- package/dist/chunk-JKP5GH6T.js.map +1 -0
- package/dist/chunk-KCBMVQL5.js +38 -0
- package/dist/chunk-KCBMVQL5.js.map +1 -0
- package/dist/chunk-KVSW5KYP.js +78 -0
- package/dist/chunk-KVSW5KYP.js.map +1 -0
- package/dist/chunk-LAWMH22O.js +172 -0
- package/dist/chunk-LAWMH22O.js.map +1 -0
- package/dist/chunk-LB7OS35Q.js +72 -0
- package/dist/chunk-LB7OS35Q.js.map +1 -0
- package/dist/chunk-LUSIFBXO.js +57 -0
- package/dist/chunk-LUSIFBXO.js.map +1 -0
- package/dist/chunk-MBVNHJVN.js +44 -0
- package/dist/chunk-MBVNHJVN.js.map +1 -0
- package/dist/chunk-MGNMHKX3.js +15 -0
- package/dist/chunk-MGNMHKX3.js.map +1 -0
- package/dist/chunk-N5KEREIA.js +41 -0
- package/dist/chunk-N5KEREIA.js.map +1 -0
- package/dist/chunk-NDSQYIWT.js +71 -0
- package/dist/chunk-NDSQYIWT.js.map +1 -0
- package/dist/chunk-NUZ4OMU3.js +28 -0
- package/dist/chunk-NUZ4OMU3.js.map +1 -0
- package/dist/chunk-QOV2R2WT.js +170 -0
- package/dist/chunk-QOV2R2WT.js.map +1 -0
- package/dist/chunk-SEFSL2GF.js +78 -0
- package/dist/chunk-SEFSL2GF.js.map +1 -0
- package/dist/chunk-T6ARFSBZ.js +103 -0
- package/dist/chunk-T6ARFSBZ.js.map +1 -0
- package/dist/chunk-TBP6BICL.js +46 -0
- package/dist/chunk-TBP6BICL.js.map +1 -0
- package/dist/chunk-TDNNOR6D.js +97 -0
- package/dist/chunk-TDNNOR6D.js.map +1 -0
- package/dist/chunk-TSPZOMHC.js +195 -0
- package/dist/chunk-TSPZOMHC.js.map +1 -0
- package/dist/chunk-UNTPVD36.js +55 -0
- package/dist/chunk-UNTPVD36.js.map +1 -0
- package/dist/chunk-VRUJH4BO.js +88 -0
- package/dist/chunk-VRUJH4BO.js.map +1 -0
- package/dist/chunk-VZ7AMAFL.js +76 -0
- package/dist/chunk-VZ7AMAFL.js.map +1 -0
- package/dist/chunk-XFXDXEUN.js +24 -0
- package/dist/chunk-XFXDXEUN.js.map +1 -0
- package/dist/chunk-YZAA4LYG.js +169 -0
- package/dist/chunk-YZAA4LYG.js.map +1 -0
- package/dist/chunk-Z73NYSBZ.js +92 -0
- package/dist/chunk-Z73NYSBZ.js.map +1 -0
- package/dist/chunk-ZJRYBOEE.js +125 -0
- package/dist/chunk-ZJRYBOEE.js.map +1 -0
- package/dist/cli.js +5798 -0
- package/dist/cli.js.map +1 -0
- package/dist/db-BxaevAyc.d.ts +683 -0
- package/dist/index.d.ts +254 -0
- package/dist/index.js +1271 -0
- package/dist/index.js.map +1 -0
- package/dist/postinstall.js +167 -0
- package/dist/postinstall.js.map +1 -0
- package/dist/queries/affected.d.ts +14 -0
- package/dist/queries/affected.js +9 -0
- package/dist/queries/affected.js.map +1 -0
- package/dist/queries/bottlenecks.d.ts +18 -0
- package/dist/queries/bottlenecks.js +8 -0
- package/dist/queries/bottlenecks.js.map +1 -0
- package/dist/queries/by-kind.d.ts +20 -0
- package/dist/queries/by-kind.js +10 -0
- package/dist/queries/by-kind.js.map +1 -0
- package/dist/queries/call-graph.d.ts +13 -0
- package/dist/queries/call-graph.js +9 -0
- package/dist/queries/call-graph.js.map +1 -0
- package/dist/queries/change-surface.d.ts +10 -0
- package/dist/queries/change-surface.js +9 -0
- package/dist/queries/change-surface.js.map +1 -0
- package/dist/queries/clean-signature.d.ts +9 -0
- package/dist/queries/clean-signature.js +7 -0
- package/dist/queries/clean-signature.js.map +1 -0
- package/dist/queries/code.d.ts +17 -0
- package/dist/queries/code.js +9 -0
- package/dist/queries/code.js.map +1 -0
- package/dist/queries/complexity-hotspots.d.ts +19 -0
- package/dist/queries/complexity-hotspots.js +9 -0
- package/dist/queries/complexity-hotspots.js.map +1 -0
- package/dist/queries/complexity.d.ts +13 -0
- package/dist/queries/complexity.js +9 -0
- package/dist/queries/complexity.js.map +1 -0
- package/dist/queries/convergence.d.ts +11 -0
- package/dist/queries/convergence.js +9 -0
- package/dist/queries/convergence.js.map +1 -0
- package/dist/queries/coupling.d.ts +17 -0
- package/dist/queries/coupling.js +9 -0
- package/dist/queries/coupling.js.map +1 -0
- package/dist/queries/cycles.d.ts +16 -0
- package/dist/queries/cycles.js +8 -0
- package/dist/queries/cycles.js.map +1 -0
- package/dist/queries/dataflow.d.ts +19 -0
- package/dist/queries/dataflow.js +9 -0
- package/dist/queries/dataflow.js.map +1 -0
- package/dist/queries/dead.d.ts +10 -0
- package/dist/queries/dead.js +9 -0
- package/dist/queries/dead.js.map +1 -0
- package/dist/queries/deep-chains.d.ts +16 -0
- package/dist/queries/deep-chains.js +8 -0
- package/dist/queries/deep-chains.js.map +1 -0
- package/dist/queries/deps.d.ts +9 -0
- package/dist/queries/deps.js +9 -0
- package/dist/queries/deps.js.map +1 -0
- package/dist/queries/diff-impact.d.ts +13 -0
- package/dist/queries/diff-impact.js +9 -0
- package/dist/queries/diff-impact.js.map +1 -0
- package/dist/queries/doc-coverage.d.ts +14 -0
- package/dist/queries/doc-coverage.js +8 -0
- package/dist/queries/doc-coverage.js.map +1 -0
- package/dist/queries/drift.d.ts +25 -0
- package/dist/queries/drift.js +8 -0
- package/dist/queries/drift.js.map +1 -0
- package/dist/queries/extract-candidates.d.ts +25 -0
- package/dist/queries/extract-candidates.js +9 -0
- package/dist/queries/extract-candidates.js.map +1 -0
- package/dist/queries/fan.d.ts +29 -0
- package/dist/queries/fan.js +14 -0
- package/dist/queries/fan.js.map +1 -0
- package/dist/queries/files.d.ts +6 -0
- package/dist/queries/files.js +7 -0
- package/dist/queries/files.js.map +1 -0
- package/dist/queries/health.d.ts +18 -0
- package/dist/queries/health.js +21 -0
- package/dist/queries/health.js.map +1 -0
- package/dist/queries/hierarchy.d.ts +13 -0
- package/dist/queries/hierarchy.js +8 -0
- package/dist/queries/hierarchy.js.map +1 -0
- package/dist/queries/hotspots.d.ts +13 -0
- package/dist/queries/hotspots.js +8 -0
- package/dist/queries/hotspots.js.map +1 -0
- package/dist/queries/imports.d.ts +19 -0
- package/dist/queries/imports.js +12 -0
- package/dist/queries/imports.js.map +1 -0
- package/dist/queries/index.d.ts +47 -0
- package/dist/queries/index.js +207 -0
- package/dist/queries/index.js.map +1 -0
- package/dist/queries/isolated.d.ts +14 -0
- package/dist/queries/isolated.js +9 -0
- package/dist/queries/isolated.js.map +1 -0
- package/dist/queries/members.d.ts +10 -0
- package/dist/queries/members.js +8 -0
- package/dist/queries/members.js.map +1 -0
- package/dist/queries/methods.d.ts +6 -0
- package/dist/queries/methods.js +8 -0
- package/dist/queries/methods.js.map +1 -0
- package/dist/queries/outline.d.ts +10 -0
- package/dist/queries/outline.js +8 -0
- package/dist/queries/outline.js.map +1 -0
- package/dist/queries/passthrough-candidates.d.ts +18 -0
- package/dist/queries/passthrough-candidates.js +9 -0
- package/dist/queries/passthrough-candidates.js.map +1 -0
- package/dist/queries/redundant-reexports.d.ts +22 -0
- package/dist/queries/redundant-reexports.js +8 -0
- package/dist/queries/redundant-reexports.js.map +1 -0
- package/dist/queries/refs.d.ts +6 -0
- package/dist/queries/refs.js +7 -0
- package/dist/queries/refs.js.map +1 -0
- package/dist/queries/similar-chains.d.ts +29 -0
- package/dist/queries/similar-chains.js +8 -0
- package/dist/queries/similar-chains.js.map +1 -0
- package/dist/queries/similar-files.d.ts +19 -0
- package/dist/queries/similar-files.js +8 -0
- package/dist/queries/similar-files.js.map +1 -0
- package/dist/queries/similar-signatures.d.ts +21 -0
- package/dist/queries/similar-signatures.js +8 -0
- package/dist/queries/similar-signatures.js.map +1 -0
- package/dist/queries/similar.d.ts +34 -0
- package/dist/queries/similar.js +11 -0
- package/dist/queries/similar.js.map +1 -0
- package/dist/queries/slice.d.ts +21 -0
- package/dist/queries/slice.js +9 -0
- package/dist/queries/slice.js.map +1 -0
- package/dist/queries/stale-abstractions.d.ts +18 -0
- package/dist/queries/stale-abstractions.js +9 -0
- package/dist/queries/stale-abstractions.js.map +1 -0
- package/dist/queries/stats.d.ts +6 -0
- package/dist/queries/stats.js +7 -0
- package/dist/queries/stats.js.map +1 -0
- package/dist/queries/surface.d.ts +7 -0
- package/dist/queries/surface.js +8 -0
- package/dist/queries/surface.js.map +1 -0
- package/dist/queries/symbols.d.ts +6 -0
- package/dist/queries/symbols.js +9 -0
- package/dist/queries/symbols.js.map +1 -0
- package/dist/queries/system.d.ts +7 -0
- package/dist/queries/system.js +9 -0
- package/dist/queries/system.js.map +1 -0
- package/dist/queries/test-coverage.d.ts +22 -0
- package/dist/queries/test-coverage.js +11 -0
- package/dist/queries/test-coverage.js.map +1 -0
- package/dist/queries/trace.d.ts +6 -0
- package/dist/queries/trace.js +8 -0
- package/dist/queries/trace.js.map +1 -0
- package/dist/queries/wrapper-candidates.d.ts +17 -0
- package/dist/queries/wrapper-candidates.js +9 -0
- package/dist/queries/wrapper-candidates.js.map +1 -0
- package/dist/reindex-worker.js +368 -0
- package/dist/reindex-worker.js.map +1 -0
- package/docs/AGENT_GUIDE.md +359 -0
- package/package.json +70 -0
- package/reports/debloat/2026-04-10-scip-query-self-audit.md +161 -0
- package/skills/concrete-plan/SKILL.md +318 -0
- package/skills/scip-debloat/SKILL.md +413 -0
- package/skills/scip-explore/SKILL.md +235 -0
- package/skills/scip-verify/SKILL.md +323 -0
- package/src/cli.ts +1480 -0
- package/src/config.ts +117 -0
- package/src/db.ts +127 -0
- package/src/gitignore-filter.ts +143 -0
- package/src/index.ts +11 -0
- package/src/postinstall.ts +8 -0
- package/src/queries/affected.ts +86 -0
- package/src/queries/bottlenecks.ts +67 -0
- package/src/queries/by-kind.ts +204 -0
- package/src/queries/call-graph.ts +66 -0
- package/src/queries/change-surface.ts +110 -0
- package/src/queries/clean-signature.ts +22 -0
- package/src/queries/code.ts +101 -0
- package/src/queries/complexity-hotspots.ts +119 -0
- package/src/queries/complexity.ts +152 -0
- package/src/queries/convergence.ts +82 -0
- package/src/queries/coupling.ts +99 -0
- package/src/queries/cycles.ts +78 -0
- package/src/queries/dataflow.ts +128 -0
- package/src/queries/dead.ts +122 -0
- package/src/queries/deep-chains.ts +59 -0
- package/src/queries/deps.ts +46 -0
- package/src/queries/diff-impact.ts +204 -0
- package/src/queries/doc-coverage.ts +86 -0
- package/src/queries/drift.ts +224 -0
- package/src/queries/extract-candidates.ts +167 -0
- package/src/queries/fan.ts +148 -0
- package/src/queries/files.ts +16 -0
- package/src/queries/health.ts +324 -0
- package/src/queries/hierarchy.ts +49 -0
- package/src/queries/hotspots.ts +53 -0
- package/src/queries/imports.ts +95 -0
- package/src/queries/index.ts +45 -0
- package/src/queries/isolated.ts +67 -0
- package/src/queries/members.ts +54 -0
- package/src/queries/methods.ts +27 -0
- package/src/queries/outline.ts +52 -0
- package/src/queries/passthrough-candidates.ts +94 -0
- package/src/queries/redundant-reexports.ts +170 -0
- package/src/queries/refs.ts +27 -0
- package/src/queries/similar-chains.ts +314 -0
- package/src/queries/similar-files.ts +140 -0
- package/src/queries/similar-signatures.ts +151 -0
- package/src/queries/similar.ts +305 -0
- package/src/queries/slice.ts +154 -0
- package/src/queries/stale-abstractions.ts +82 -0
- package/src/queries/stats.ts +22 -0
- package/src/queries/surface.ts +34 -0
- package/src/queries/symbols.ts +39 -0
- package/src/queries/system.ts +86 -0
- package/src/queries/test-coverage.ts +106 -0
- package/src/queries/trace.ts +55 -0
- package/src/queries/wrapper-candidates.ts +112 -0
- package/src/query-support.ts +226 -0
- package/src/reindex/detect.ts +58 -0
- package/src/reindex/index.ts +153 -0
- package/src/reindex/indexers.ts +220 -0
- package/src/reindex/install.ts +125 -0
- package/src/reindex-worker.ts +35 -0
- package/src/setup.ts +202 -0
- package/src/symbol-parser.ts +278 -0
- package/src/types.ts +654 -0
- package/src/watch.ts +274 -0
- package/tests/gitignore-filter.test.ts +48 -0
- package/tests/queries.test.ts +300 -0
- package/tests/symbol-parser.test.ts +157 -0
- package/tsconfig.json +20 -0
- package/tsup.config.ts +40 -0
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import type { ScipDatabase } from '../db.js';
|
|
2
|
+
import type { ByKindResult } from '../types.js';
|
|
3
|
+
import { shortenSymbol } from '../symbol-parser.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* SCIP SymbolInformation.Kind enum values.
|
|
7
|
+
* From: https://github.com/sourcegraph/scip/blob/main/scip.proto
|
|
8
|
+
*/
|
|
9
|
+
const KIND_NAMES: Record<number, string> = {
|
|
10
|
+
0: 'UnspecifiedKind',
|
|
11
|
+
1: 'AbstractMethod',
|
|
12
|
+
2: 'Accessor',
|
|
13
|
+
3: 'Array',
|
|
14
|
+
4: 'Assertion',
|
|
15
|
+
5: 'AssociatedType',
|
|
16
|
+
6: 'Attribute',
|
|
17
|
+
7: 'Axiom',
|
|
18
|
+
8: 'Boolean',
|
|
19
|
+
9: 'Class',
|
|
20
|
+
10: 'Constant',
|
|
21
|
+
11: 'Constructor',
|
|
22
|
+
12: 'Contract',
|
|
23
|
+
13: 'DataFamily',
|
|
24
|
+
14: 'DefinitionMacro',
|
|
25
|
+
15: 'Delegate',
|
|
26
|
+
16: 'Enum',
|
|
27
|
+
17: 'EnumMember',
|
|
28
|
+
18: 'Error',
|
|
29
|
+
19: 'Event',
|
|
30
|
+
20: 'Fact',
|
|
31
|
+
21: 'Field',
|
|
32
|
+
22: 'File',
|
|
33
|
+
23: 'Function',
|
|
34
|
+
24: 'Getter',
|
|
35
|
+
25: 'Grammar',
|
|
36
|
+
26: 'Instance',
|
|
37
|
+
27: 'Interface',
|
|
38
|
+
28: 'Key',
|
|
39
|
+
29: 'Lang',
|
|
40
|
+
30: 'Lemma',
|
|
41
|
+
31: 'Library',
|
|
42
|
+
32: 'Macro',
|
|
43
|
+
33: 'Method',
|
|
44
|
+
34: 'MethodAlias',
|
|
45
|
+
35: 'MethodReceiver',
|
|
46
|
+
36: 'MethodSpecification',
|
|
47
|
+
37: 'Message',
|
|
48
|
+
38: 'Modifier',
|
|
49
|
+
39: 'Module',
|
|
50
|
+
40: 'Namespace',
|
|
51
|
+
41: 'Null',
|
|
52
|
+
42: 'Number',
|
|
53
|
+
43: 'Object',
|
|
54
|
+
44: 'Operator',
|
|
55
|
+
45: 'Package',
|
|
56
|
+
46: 'PackageObject',
|
|
57
|
+
47: 'Parameter',
|
|
58
|
+
48: 'ParameterLabel',
|
|
59
|
+
49: 'Pattern',
|
|
60
|
+
50: 'Predicate',
|
|
61
|
+
51: 'Property',
|
|
62
|
+
52: 'Protocol',
|
|
63
|
+
53: 'ProtocolMethod',
|
|
64
|
+
54: 'PureVirtualMethod',
|
|
65
|
+
55: 'Quasiquoter',
|
|
66
|
+
56: 'SelfParameter',
|
|
67
|
+
57: 'Setter',
|
|
68
|
+
58: 'Signature',
|
|
69
|
+
59: 'SingletonClass',
|
|
70
|
+
60: 'SingletonMethod',
|
|
71
|
+
61: 'StaticDataMember',
|
|
72
|
+
62: 'StaticEvent',
|
|
73
|
+
63: 'StaticField',
|
|
74
|
+
64: 'StaticMethod',
|
|
75
|
+
65: 'StaticProperty',
|
|
76
|
+
66: 'StaticVariable',
|
|
77
|
+
67: 'String',
|
|
78
|
+
68: 'Struct',
|
|
79
|
+
69: 'Subscript',
|
|
80
|
+
70: 'Tactic',
|
|
81
|
+
71: 'Theorem',
|
|
82
|
+
72: 'ThisParameter',
|
|
83
|
+
73: 'Trait',
|
|
84
|
+
74: 'TraitMethod',
|
|
85
|
+
75: 'Type',
|
|
86
|
+
76: 'TypeAlias',
|
|
87
|
+
77: 'TypeClass',
|
|
88
|
+
78: 'TypeClassMethod',
|
|
89
|
+
79: 'TypeFamily',
|
|
90
|
+
80: 'TypeParameter',
|
|
91
|
+
81: 'Union',
|
|
92
|
+
82: 'Value',
|
|
93
|
+
83: 'Variable',
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/** Reverse lookup: name -> kind number */
|
|
97
|
+
const KIND_BY_NAME = new Map<string, number>();
|
|
98
|
+
for (const [k, v] of Object.entries(KIND_NAMES)) {
|
|
99
|
+
KIND_BY_NAME.set(v.toLowerCase(), Number(k));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Find symbols by SCIP kind (class, interface, enum, function, etc.)
|
|
104
|
+
*/
|
|
105
|
+
export function byKind(
|
|
106
|
+
db: ScipDatabase,
|
|
107
|
+
kindQuery: string,
|
|
108
|
+
opts: { scope?: string; limit?: number } = {},
|
|
109
|
+
): ByKindResult[] {
|
|
110
|
+
const { scope, limit = 100 } = opts;
|
|
111
|
+
|
|
112
|
+
// Resolve kind: accept number or name
|
|
113
|
+
let kindNum: number | null = null;
|
|
114
|
+
const asNum = parseInt(kindQuery, 10);
|
|
115
|
+
if (!isNaN(asNum)) {
|
|
116
|
+
kindNum = asNum;
|
|
117
|
+
} else {
|
|
118
|
+
kindNum = KIND_BY_NAME.get(kindQuery.toLowerCase()) ?? null;
|
|
119
|
+
// Fuzzy match: try partial name
|
|
120
|
+
if (kindNum === null) {
|
|
121
|
+
for (const [name, num] of KIND_BY_NAME) {
|
|
122
|
+
if (name.includes(kindQuery.toLowerCase())) {
|
|
123
|
+
kindNum = num;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (kindNum === null) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : '';
|
|
135
|
+
|
|
136
|
+
// Check if the index actually has kind data populated
|
|
137
|
+
const hasKinds = db.get<{ c: number }>(
|
|
138
|
+
`SELECT COUNT(*) AS c FROM global_symbols WHERE kind IS NOT NULL`,
|
|
139
|
+
);
|
|
140
|
+
if (!hasKinds || hasKinds.c === 0) {
|
|
141
|
+
return []; // Indexer doesn't populate kind field
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const rows = db.all<{
|
|
145
|
+
symbol: string;
|
|
146
|
+
kind: number;
|
|
147
|
+
relative_path: string;
|
|
148
|
+
start_line: number;
|
|
149
|
+
end_line: number;
|
|
150
|
+
}>(
|
|
151
|
+
`SELECT gs.symbol, gs.kind, d.relative_path, der.start_line, der.end_line
|
|
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 gs.kind = ?
|
|
156
|
+
${db.pathExclusionsFor('d')}
|
|
157
|
+
${scopeFilter}
|
|
158
|
+
ORDER BY d.relative_path, der.start_line
|
|
159
|
+
LIMIT ?`,
|
|
160
|
+
kindNum, limit,
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
return rows
|
|
164
|
+
.filter((r) => !db.isIgnored(r.relative_path))
|
|
165
|
+
.map((r) => ({
|
|
166
|
+
symbol: r.symbol,
|
|
167
|
+
shortName: shortenSymbol(r.symbol),
|
|
168
|
+
kind: r.kind,
|
|
169
|
+
kindName: KIND_NAMES[r.kind] ?? 'Unknown',
|
|
170
|
+
relativePath: r.relative_path,
|
|
171
|
+
startLine: r.start_line,
|
|
172
|
+
endLine: r.end_line,
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** List all symbol kinds present in the index with counts */
|
|
177
|
+
export function kindCounts(
|
|
178
|
+
db: ScipDatabase,
|
|
179
|
+
opts: { scope?: string } = {},
|
|
180
|
+
): Array<{ kind: number; kindName: string; count: number }> {
|
|
181
|
+
const scopeFilter = opts.scope
|
|
182
|
+
? `AND d.relative_path LIKE '%${opts.scope}%'`
|
|
183
|
+
: '';
|
|
184
|
+
|
|
185
|
+
const rows = db.all<{ kind: number; cnt: number }>(
|
|
186
|
+
`SELECT gs.kind, COUNT(*) AS cnt
|
|
187
|
+
FROM global_symbols gs
|
|
188
|
+
JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
|
|
189
|
+
JOIN documents d ON der.document_id = d.id
|
|
190
|
+
WHERE 1 = 1
|
|
191
|
+
${db.pathExclusionsFor('d')}
|
|
192
|
+
AND gs.kind IS NOT NULL
|
|
193
|
+
AND gs.kind != 0
|
|
194
|
+
${scopeFilter}
|
|
195
|
+
GROUP BY gs.kind
|
|
196
|
+
ORDER BY cnt DESC`,
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
return rows.map((r) => ({
|
|
200
|
+
kind: r.kind,
|
|
201
|
+
kindName: KIND_NAMES[r.kind] ?? 'Unknown',
|
|
202
|
+
count: r.cnt,
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ScipDatabase } from '../db.js';
|
|
2
|
+
import { findFirstSymbolMatch, getCalleeRowsForSymbol } from '../query-support.js';
|
|
3
|
+
import type { CallGraphResult } from '../types.js';
|
|
4
|
+
import { shortenSymbol } from '../symbol-parser.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Build a call graph for a symbol: who calls it (incoming) and
|
|
8
|
+
* what it calls (outgoing).
|
|
9
|
+
*
|
|
10
|
+
* Incoming: other symbols whose definition ranges contain a reference to this symbol.
|
|
11
|
+
* Outgoing: symbols referenced within this symbol's definition range.
|
|
12
|
+
*/
|
|
13
|
+
export function callGraph(db: ScipDatabase, symbolPattern: string): CallGraphResult | null {
|
|
14
|
+
// Find the target symbol and its definition range
|
|
15
|
+
const target = findFirstSymbolMatch(db, symbolPattern);
|
|
16
|
+
|
|
17
|
+
if (!target) return null;
|
|
18
|
+
|
|
19
|
+
// CALLERS: symbols whose definition ranges contain a reference to our target.
|
|
20
|
+
// Find chunks that reference our symbol, then find which symbol's definition encloses that chunk.
|
|
21
|
+
const callerRows = db.all<{
|
|
22
|
+
caller_symbol: string;
|
|
23
|
+
caller_file: string;
|
|
24
|
+
}>(
|
|
25
|
+
`SELECT DISTINCT caller_gs.symbol AS caller_symbol, caller_d.relative_path AS caller_file
|
|
26
|
+
FROM mentions m
|
|
27
|
+
JOIN chunks c ON m.chunk_id = c.id
|
|
28
|
+
JOIN documents ref_d ON c.document_id = ref_d.id
|
|
29
|
+
-- Find the enclosing symbol for where the reference appears
|
|
30
|
+
JOIN defn_enclosing_ranges caller_der
|
|
31
|
+
ON caller_der.document_id = ref_d.id
|
|
32
|
+
AND c.start_line >= caller_der.start_line
|
|
33
|
+
AND c.end_line <= caller_der.end_line
|
|
34
|
+
JOIN global_symbols caller_gs ON caller_der.symbol_id = caller_gs.id
|
|
35
|
+
JOIN documents caller_d ON caller_der.document_id = caller_d.id
|
|
36
|
+
WHERE m.symbol_id = ?
|
|
37
|
+
AND m.role = 0
|
|
38
|
+
AND caller_gs.id != ?
|
|
39
|
+
${db.symbolNoiseFor('caller_gs')}
|
|
40
|
+
${db.pathExclusionsFor('caller_d')}
|
|
41
|
+
ORDER BY caller_d.relative_path
|
|
42
|
+
LIMIT 50`,
|
|
43
|
+
target.symbolId, target.symbolId,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// CALLEES: symbols referenced within our target's definition range.
|
|
47
|
+
const calleeRows = getCalleeRowsForSymbol(db, target, { limit: 50 });
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
symbol: target.symbol,
|
|
51
|
+
shortName: shortenSymbol(target.symbol),
|
|
52
|
+
callers: callerRows
|
|
53
|
+
.filter((r) => !db.isIgnored(r.caller_file))
|
|
54
|
+
.map((r) => ({
|
|
55
|
+
symbol: r.caller_symbol,
|
|
56
|
+
shortName: shortenSymbol(r.caller_symbol),
|
|
57
|
+
file: r.caller_file,
|
|
58
|
+
})),
|
|
59
|
+
callees: calleeRows
|
|
60
|
+
.map((r) => ({
|
|
61
|
+
symbol: r.symbol,
|
|
62
|
+
shortName: shortenSymbol(r.symbol),
|
|
63
|
+
file: r.file,
|
|
64
|
+
})),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { ScipDatabase } from '../db.js';
|
|
2
|
+
import { TEST_FILE_PATTERNS, testFileMatchSql } from '../query-support.js';
|
|
3
|
+
import type { ChangeSurfaceEntry, ChangeSurfaceResult } from '../types.js';
|
|
4
|
+
import { shortenSymbol } from '../symbol-parser.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Pre-change briefing for a file. For each symbol defined in the file,
|
|
8
|
+
* reports external consumer count, test coverage, and risk level.
|
|
9
|
+
*/
|
|
10
|
+
export function changeSurface(
|
|
11
|
+
db: ScipDatabase,
|
|
12
|
+
filePattern: string,
|
|
13
|
+
): ChangeSurfaceResult | null {
|
|
14
|
+
// Find the file
|
|
15
|
+
const doc = db.get<{ id: number; relative_path: string }>(
|
|
16
|
+
`SELECT id, relative_path FROM documents
|
|
17
|
+
WHERE relative_path LIKE ?
|
|
18
|
+
${db.pathExclusionsFor('documents')}
|
|
19
|
+
LIMIT 1`,
|
|
20
|
+
`%${filePattern}%`,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
if (!doc || db.isIgnored(doc.relative_path)) return null;
|
|
24
|
+
|
|
25
|
+
// Get all symbols defined in this file, excluding typeLiterals
|
|
26
|
+
const syms = db.all<{
|
|
27
|
+
symbol_id: number;
|
|
28
|
+
symbol: string;
|
|
29
|
+
start_line: number;
|
|
30
|
+
end_line: number;
|
|
31
|
+
}>(
|
|
32
|
+
`SELECT DISTINCT gs.id AS symbol_id, gs.symbol, der.start_line, der.end_line
|
|
33
|
+
FROM defn_enclosing_ranges der
|
|
34
|
+
JOIN global_symbols gs ON der.symbol_id = gs.id
|
|
35
|
+
WHERE der.document_id = ?
|
|
36
|
+
${db.symbolNoiseFor('gs')}
|
|
37
|
+
ORDER BY der.start_line`,
|
|
38
|
+
doc.id,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const testPatternSql = testFileMatchSql('ref_d', TEST_FILE_PATTERNS);
|
|
42
|
+
|
|
43
|
+
const symbols: ChangeSurfaceEntry[] = [];
|
|
44
|
+
let totalExternalConsumers = 0;
|
|
45
|
+
let coveredCount = 0;
|
|
46
|
+
|
|
47
|
+
for (const sym of syms) {
|
|
48
|
+
// Count external consumers: mentions with role=0 from different documents
|
|
49
|
+
const consumerRow = db.get<{ consumer_count: number }>(
|
|
50
|
+
`SELECT COUNT(DISTINCT c.document_id) AS consumer_count
|
|
51
|
+
FROM mentions m
|
|
52
|
+
JOIN chunks c ON m.chunk_id = c.id
|
|
53
|
+
WHERE m.symbol_id = ?
|
|
54
|
+
AND m.role = 0
|
|
55
|
+
AND c.document_id != ?`,
|
|
56
|
+
sym.symbol_id,
|
|
57
|
+
doc.id,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const externalConsumers = consumerRow?.consumer_count ?? 0;
|
|
61
|
+
|
|
62
|
+
// Find test files that reference this symbol
|
|
63
|
+
const testFiles = db.all<{ relative_path: string }>(
|
|
64
|
+
`SELECT DISTINCT ref_d.relative_path
|
|
65
|
+
FROM mentions m
|
|
66
|
+
JOIN chunks c ON m.chunk_id = c.id
|
|
67
|
+
JOIN documents ref_d ON c.document_id = ref_d.id
|
|
68
|
+
WHERE m.symbol_id = ?
|
|
69
|
+
AND m.role = 0
|
|
70
|
+
AND (${testPatternSql})
|
|
71
|
+
ORDER BY ref_d.relative_path`,
|
|
72
|
+
sym.symbol_id,
|
|
73
|
+
).map((r) => r.relative_path);
|
|
74
|
+
|
|
75
|
+
const hasTests = testFiles.length > 0;
|
|
76
|
+
if (hasTests) coveredCount++;
|
|
77
|
+
|
|
78
|
+
// Risk level determination
|
|
79
|
+
let riskLevel: 'low' | 'medium' | 'high';
|
|
80
|
+
if (externalConsumers > 10 && !hasTests) {
|
|
81
|
+
riskLevel = 'high';
|
|
82
|
+
} else if (externalConsumers > 5 || !hasTests) {
|
|
83
|
+
riskLevel = 'medium';
|
|
84
|
+
} else {
|
|
85
|
+
riskLevel = 'low';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
totalExternalConsumers += externalConsumers;
|
|
89
|
+
|
|
90
|
+
symbols.push({
|
|
91
|
+
symbol: sym.symbol,
|
|
92
|
+
shortName: shortenSymbol(sym.symbol),
|
|
93
|
+
startLine: sym.start_line,
|
|
94
|
+
endLine: sym.end_line,
|
|
95
|
+
externalConsumers,
|
|
96
|
+
testFiles,
|
|
97
|
+
riskLevel,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const testCoveragePercent =
|
|
102
|
+
symbols.length > 0 ? Math.round((coveredCount / symbols.length) * 100) : 0;
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
file: doc.relative_path,
|
|
106
|
+
symbols,
|
|
107
|
+
totalExternalConsumers,
|
|
108
|
+
testCoveragePercent,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean up the raw doc/signature string from the SCIP index.
|
|
3
|
+
*
|
|
4
|
+
* Shared across symbols, trace, and system queries.
|
|
5
|
+
* Previously duplicated as cleanSig/cleanSignature in three files.
|
|
6
|
+
*/
|
|
7
|
+
export function cleanSignature(sig: string | null): string | null {
|
|
8
|
+
if (!sig || !sig.trim()) return null;
|
|
9
|
+
return sig
|
|
10
|
+
.replace(/^```\w*\s*/, '')
|
|
11
|
+
.replace(/\s*```$/, '')
|
|
12
|
+
.replace(/^\(method\)\s*/, '')
|
|
13
|
+
.replace(/^\(property\)\s*/, '')
|
|
14
|
+
.replace(/^\(function\)\s*/, '')
|
|
15
|
+
.replace(/^\(class\)\s*/, '')
|
|
16
|
+
.replace(/^\(interface\)\s*/, '')
|
|
17
|
+
.replace(/^\(enum\)\s*/, '')
|
|
18
|
+
.replace(/^\(type alias\)\s*/, '')
|
|
19
|
+
.replace(/^\(const\)\s*/, '')
|
|
20
|
+
.replace(/^\(var\)\s*/, '')
|
|
21
|
+
.trim() || null;
|
|
22
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import type { ScipDatabase } from '../db.js';
|
|
4
|
+
import { findFirstSymbolMatch } from '../query-support.js';
|
|
5
|
+
import type { CodeResult } from '../types.js';
|
|
6
|
+
import { shortenSymbol } from '../symbol-parser.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Read the source code for a symbol, bounded to its definition range.
|
|
10
|
+
* Language-agnostic: just reads the file and extracts the relevant lines.
|
|
11
|
+
*
|
|
12
|
+
* Accepts:
|
|
13
|
+
* - Symbol name pattern: "processVegaMention"
|
|
14
|
+
* - Full short name: "src:modules:chat:processVegaMention"
|
|
15
|
+
* - File:line-line syntax: "src/chat/service.ts:100-200"
|
|
16
|
+
*/
|
|
17
|
+
export function code(
|
|
18
|
+
db: ScipDatabase,
|
|
19
|
+
symbolPattern: string,
|
|
20
|
+
opts: { context?: number } = {},
|
|
21
|
+
): CodeResult | null {
|
|
22
|
+
const { context = 0 } = opts;
|
|
23
|
+
|
|
24
|
+
// Handle direct file:line-line syntax (bypass symbol lookup)
|
|
25
|
+
const fileLineMatch = symbolPattern.match(/^(.+\.\w+):(\d+)-(\d+)$/);
|
|
26
|
+
if (fileLineMatch) {
|
|
27
|
+
return readFileRange(db, fileLineMatch[1]!, parseInt(fileLineMatch[2]!, 10), parseInt(fileLineMatch[3]!, 10), context);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const match = findFirstSymbolMatch(db, symbolPattern);
|
|
31
|
+
if (!match) return null;
|
|
32
|
+
|
|
33
|
+
// Get the language from the documents table
|
|
34
|
+
const doc = db.get<{ language: string | null }>(
|
|
35
|
+
`SELECT language FROM documents WHERE relative_path = ?`,
|
|
36
|
+
match.relativePath,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// Read the file
|
|
40
|
+
const filePath = join(db.config.projectRoot, match.relativePath);
|
|
41
|
+
let fileContent: string;
|
|
42
|
+
try {
|
|
43
|
+
fileContent = readFileSync(filePath, 'utf-8');
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const lines = fileContent.split('\n');
|
|
49
|
+
const startLine = Math.max(0, match.startLine - context);
|
|
50
|
+
const endLine = Math.min(lines.length - 1, match.endLine + context);
|
|
51
|
+
const source = lines.slice(startLine, endLine + 1).join('\n');
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
symbol: match.symbol,
|
|
55
|
+
shortName: shortenSymbol(match.symbol),
|
|
56
|
+
relativePath: match.relativePath,
|
|
57
|
+
startLine: startLine + 1, // 1-indexed for display
|
|
58
|
+
endLine: endLine + 1,
|
|
59
|
+
language: doc?.language ?? null,
|
|
60
|
+
source,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Read source by file path and line range directly (no symbol lookup) */
|
|
65
|
+
function readFileRange(
|
|
66
|
+
db: ScipDatabase,
|
|
67
|
+
filePath: string,
|
|
68
|
+
startLine: number,
|
|
69
|
+
endLine: number,
|
|
70
|
+
context: number,
|
|
71
|
+
): CodeResult | null {
|
|
72
|
+
// Find the file in the index
|
|
73
|
+
const doc = db.get<{ relative_path: string; language: string | null }>(
|
|
74
|
+
`SELECT relative_path, language FROM documents WHERE relative_path LIKE ?`,
|
|
75
|
+
`%${filePath}%`,
|
|
76
|
+
);
|
|
77
|
+
if (!doc) return null;
|
|
78
|
+
|
|
79
|
+
const fullPath = join(db.config.projectRoot, doc.relative_path);
|
|
80
|
+
let fileContent: string;
|
|
81
|
+
try {
|
|
82
|
+
fileContent = readFileSync(fullPath, 'utf-8');
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const lines = fileContent.split('\n');
|
|
88
|
+
const start = Math.max(0, startLine - 1 - context); // convert to 0-indexed
|
|
89
|
+
const end = Math.min(lines.length - 1, endLine - 1 + context);
|
|
90
|
+
const source = lines.slice(start, end + 1).join('\n');
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
symbol: `${doc.relative_path}:${startLine}-${endLine}`,
|
|
94
|
+
shortName: `${doc.relative_path}:${startLine}-${endLine}`,
|
|
95
|
+
relativePath: doc.relative_path,
|
|
96
|
+
startLine: start + 1,
|
|
97
|
+
endLine: end + 1,
|
|
98
|
+
language: doc.language,
|
|
99
|
+
source,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { ScipDatabase } from '../db.js';
|
|
2
|
+
import { testFileExclusionSql } from '../query-support.js';
|
|
3
|
+
import type { ComplexityHotspot } from '../types.js';
|
|
4
|
+
import { shortenSymbol } from '../symbol-parser.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Find complexity hotspots: symbols with a composite score based on
|
|
8
|
+
* LOC, fan-in, fan-out, and callee count.
|
|
9
|
+
*
|
|
10
|
+
* Score = (loc / 50) * (fanIn / 5) * max(fanOut / 5, 1)
|
|
11
|
+
*
|
|
12
|
+
* High scores indicate symbols that are large, widely depended upon,
|
|
13
|
+
* AND reach out to many other modules — the riskiest code to change.
|
|
14
|
+
*/
|
|
15
|
+
export function complexityHotspots(
|
|
16
|
+
db: ScipDatabase,
|
|
17
|
+
opts?: { scope?: string; minLoc?: number; limit?: number },
|
|
18
|
+
): ComplexityHotspot[] {
|
|
19
|
+
const { scope, minLoc = 10, limit = 30 } = opts ?? {};
|
|
20
|
+
const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : '';
|
|
21
|
+
|
|
22
|
+
const rows = db.all<{
|
|
23
|
+
symbol: string;
|
|
24
|
+
file: string;
|
|
25
|
+
start_line: number;
|
|
26
|
+
end_line: number;
|
|
27
|
+
loc: number;
|
|
28
|
+
fan_in: number;
|
|
29
|
+
fan_out: number;
|
|
30
|
+
callee_count: number;
|
|
31
|
+
}>(
|
|
32
|
+
`SELECT
|
|
33
|
+
gs.symbol,
|
|
34
|
+
d.relative_path AS file,
|
|
35
|
+
der.start_line,
|
|
36
|
+
der.end_line,
|
|
37
|
+
(der.end_line - der.start_line + 1) AS loc,
|
|
38
|
+
-- fanIn: distinct files that reference this symbol
|
|
39
|
+
(SELECT COUNT(DISTINCT ref_c.document_id)
|
|
40
|
+
FROM mentions ref_m
|
|
41
|
+
JOIN chunks ref_c ON ref_m.chunk_id = ref_c.id
|
|
42
|
+
WHERE ref_m.symbol_id = gs.id AND ref_m.role = 0
|
|
43
|
+
) AS fan_in,
|
|
44
|
+
-- fanOut: distinct symbols referenced within this definition range
|
|
45
|
+
-- that are defined in different files
|
|
46
|
+
(SELECT COUNT(DISTINCT out_gs.id)
|
|
47
|
+
FROM mentions out_m
|
|
48
|
+
JOIN chunks out_c ON out_m.chunk_id = out_c.id
|
|
49
|
+
JOIN global_symbols out_gs ON out_m.symbol_id = out_gs.id
|
|
50
|
+
JOIN defn_enclosing_ranges out_der ON out_gs.id = out_der.symbol_id
|
|
51
|
+
WHERE out_c.document_id = der.document_id
|
|
52
|
+
AND out_c.start_line >= der.start_line
|
|
53
|
+
AND out_c.end_line <= der.end_line
|
|
54
|
+
AND out_m.role = 0
|
|
55
|
+
AND out_gs.id != gs.id
|
|
56
|
+
AND out_der.document_id != der.document_id
|
|
57
|
+
) AS fan_out,
|
|
58
|
+
-- calleeCount: total distinct callees within definition range
|
|
59
|
+
(SELECT COUNT(DISTINCT callee_gs.id)
|
|
60
|
+
FROM mentions callee_m
|
|
61
|
+
JOIN chunks callee_c ON callee_m.chunk_id = callee_c.id
|
|
62
|
+
JOIN global_symbols callee_gs ON callee_m.symbol_id = callee_gs.id
|
|
63
|
+
WHERE callee_c.document_id = der.document_id
|
|
64
|
+
AND callee_c.start_line >= der.start_line
|
|
65
|
+
AND callee_c.end_line <= der.end_line
|
|
66
|
+
AND callee_m.role = 0
|
|
67
|
+
AND callee_gs.id != gs.id
|
|
68
|
+
) AS callee_count
|
|
69
|
+
FROM global_symbols gs
|
|
70
|
+
JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
|
|
71
|
+
JOIN documents d ON der.document_id = d.id
|
|
72
|
+
WHERE 1 = 1
|
|
73
|
+
${db.pathExclusionsFor('d')}
|
|
74
|
+
AND ${testFileExclusionSql('d')}
|
|
75
|
+
${db.symbolNoiseFor('gs')}
|
|
76
|
+
AND (der.end_line - der.start_line + 1) >= ?
|
|
77
|
+
${scopeFilter}
|
|
78
|
+
ORDER BY (
|
|
79
|
+
CAST((der.end_line - der.start_line + 1) AS REAL) / 50.0
|
|
80
|
+
* CAST((SELECT COUNT(DISTINCT ref_c2.document_id)
|
|
81
|
+
FROM mentions ref_m2
|
|
82
|
+
JOIN chunks ref_c2 ON ref_m2.chunk_id = ref_c2.id
|
|
83
|
+
WHERE ref_m2.symbol_id = gs.id AND ref_m2.role = 0
|
|
84
|
+
) AS REAL) / 5.0
|
|
85
|
+
* MAX(CAST((SELECT COUNT(DISTINCT out_gs2.id)
|
|
86
|
+
FROM mentions out_m2
|
|
87
|
+
JOIN chunks out_c2 ON out_m2.chunk_id = out_c2.id
|
|
88
|
+
JOIN global_symbols out_gs2 ON out_m2.symbol_id = out_gs2.id
|
|
89
|
+
JOIN defn_enclosing_ranges out_der2 ON out_gs2.id = out_der2.symbol_id
|
|
90
|
+
WHERE out_c2.document_id = der.document_id
|
|
91
|
+
AND out_c2.start_line >= der.start_line
|
|
92
|
+
AND out_c2.end_line <= der.end_line
|
|
93
|
+
AND out_m2.role = 0
|
|
94
|
+
AND out_gs2.id != gs.id
|
|
95
|
+
AND out_der2.document_id != der.document_id
|
|
96
|
+
) AS REAL) / 5.0, 1.0)
|
|
97
|
+
) DESC
|
|
98
|
+
LIMIT ?`,
|
|
99
|
+
minLoc, limit,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
return rows
|
|
103
|
+
.filter((r) => !db.isIgnored(r.file))
|
|
104
|
+
.map((r) => ({
|
|
105
|
+
symbol: r.symbol,
|
|
106
|
+
shortName: shortenSymbol(r.symbol),
|
|
107
|
+
file: r.file,
|
|
108
|
+
startLine: r.start_line,
|
|
109
|
+
endLine: r.end_line,
|
|
110
|
+
loc: r.loc,
|
|
111
|
+
fanIn: r.fan_in,
|
|
112
|
+
fanOut: r.fan_out,
|
|
113
|
+
calleeCount: r.callee_count,
|
|
114
|
+
score:
|
|
115
|
+
Math.round(
|
|
116
|
+
(r.loc / 50) * (r.fan_in / 5) * Math.max(r.fan_out / 5, 1) * 100,
|
|
117
|
+
) / 100,
|
|
118
|
+
}));
|
|
119
|
+
}
|