lsp-intelligence 0.1.2 → 0.2.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 +12 -7
- package/dist/analysis/pattern/collectSearchFiles.d.ts +5 -0
- package/dist/analysis/pattern/collectSearchFiles.js +38 -0
- package/dist/analysis/pattern/collectSearchFiles.js.map +1 -0
- package/dist/analysis/pattern/runPatternSearch.d.ts +17 -0
- package/dist/analysis/pattern/runPatternSearch.js +63 -0
- package/dist/analysis/pattern/runPatternSearch.js.map +1 -0
- package/dist/analysis/ts/extractDeclarations.d.ts +7 -0
- package/dist/analysis/ts/extractDeclarations.js +93 -0
- package/dist/analysis/ts/extractDeclarations.js.map +1 -0
- package/dist/analysis/ts/extractUsages.d.ts +7 -0
- package/dist/analysis/ts/extractUsages.js +120 -0
- package/dist/analysis/ts/extractUsages.js.map +1 -0
- package/dist/analysis/ts/parseSourceFile.d.ts +10 -0
- package/dist/analysis/ts/parseSourceFile.js +28 -0
- package/dist/analysis/ts/parseSourceFile.js.map +1 -0
- package/dist/analysis/ts/snippets.d.ts +14 -0
- package/dist/analysis/ts/snippets.js +29 -0
- package/dist/analysis/ts/snippets.js.map +1 -0
- package/dist/analysis/ts/structuralPredicates.d.ts +10 -0
- package/dist/analysis/ts/structuralPredicates.js +170 -0
- package/dist/analysis/ts/structuralPredicates.js.map +1 -0
- package/dist/ast/diffDeclarationShapes.d.ts +16 -0
- package/dist/ast/diffDeclarationShapes.js +179 -0
- package/dist/ast/diffDeclarationShapes.js.map +1 -0
- package/dist/ast/extractExportDeclarations.d.ts +21 -0
- package/dist/ast/extractExportDeclarations.js +218 -0
- package/dist/ast/extractExportDeclarations.js.map +1 -0
- package/dist/ast/findNodeAtPosition.d.ts +12 -0
- package/dist/ast/findNodeAtPosition.js +75 -0
- package/dist/ast/findNodeAtPosition.js.map +1 -0
- package/dist/ast/parseFile.d.ts +10 -0
- package/dist/ast/parseFile.js +29 -0
- package/dist/ast/parseFile.js.map +1 -0
- package/dist/engine/waitForDiagnostics.d.ts +7 -0
- package/dist/engine/waitForDiagnostics.js +16 -0
- package/dist/engine/waitForDiagnostics.js.map +1 -0
- package/dist/git/getBaseFileContent.d.ts +5 -0
- package/dist/git/getBaseFileContent.js +16 -0
- package/dist/git/getBaseFileContent.js.map +1 -0
- package/dist/git/getChangedFiles.d.ts +4 -0
- package/dist/git/getChangedFiles.js +21 -0
- package/dist/git/getChangedFiles.js.map +1 -0
- package/dist/git/getChangedHunks.d.ts +13 -0
- package/dist/git/getChangedHunks.js +51 -0
- package/dist/git/getChangedHunks.js.map +1 -0
- package/dist/git/getMergeBase.d.ts +5 -0
- package/dist/git/getMergeBase.js +23 -0
- package/dist/git/getMergeBase.js.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/resolve/searchScope.d.ts +11 -0
- package/dist/resolve/searchScope.js +52 -0
- package/dist/resolve/searchScope.js.map +1 -0
- package/dist/resolve/targetResolver.d.ts +33 -0
- package/dist/resolve/targetResolver.js +84 -0
- package/dist/resolve/targetResolver.js.map +1 -0
- package/dist/search/families/behaviorFamilies.d.ts +22 -0
- package/dist/search/families/behaviorFamilies.js +90 -0
- package/dist/search/families/behaviorFamilies.js.map +1 -0
- package/dist/search/index/declarationIndex.d.ts +6 -0
- package/dist/search/index/declarationIndex.js +13 -0
- package/dist/search/index/declarationIndex.js.map +1 -0
- package/dist/search/index/types.d.ts +1 -0
- package/dist/search/index/types.js +2 -0
- package/dist/search/index/types.js.map +1 -0
- package/dist/search/index/usageIndex.d.ts +6 -0
- package/dist/search/index/usageIndex.js +13 -0
- package/dist/search/index/usageIndex.js.map +1 -0
- package/dist/search/index/workspaceIndex.d.ts +8 -0
- package/dist/search/index/workspaceIndex.js +91 -0
- package/dist/search/index/workspaceIndex.js.map +1 -0
- package/dist/search/query/parseQuery.d.ts +9 -0
- package/dist/search/query/parseQuery.js +244 -0
- package/dist/search/query/parseQuery.js.map +1 -0
- package/dist/search/query/planQuery.d.ts +9 -0
- package/dist/search/query/planQuery.js +58 -0
- package/dist/search/query/planQuery.js.map +1 -0
- package/dist/search/ranking/assessConfidence.d.ts +6 -0
- package/dist/search/ranking/assessConfidence.js +25 -0
- package/dist/search/ranking/assessConfidence.js.map +1 -0
- package/dist/search/ranking/mergeCandidates.d.ts +10 -0
- package/dist/search/ranking/mergeCandidates.js +46 -0
- package/dist/search/ranking/mergeCandidates.js.map +1 -0
- package/dist/search/ranking/rankCandidates.d.ts +12 -0
- package/dist/search/ranking/rankCandidates.js +58 -0
- package/dist/search/ranking/rankCandidates.js.map +1 -0
- package/dist/search/retrievers/behaviorRetriever.d.ts +7 -0
- package/dist/search/retrievers/behaviorRetriever.js +91 -0
- package/dist/search/retrievers/behaviorRetriever.js.map +1 -0
- package/dist/search/retrievers/identifierRetriever.d.ts +7 -0
- package/dist/search/retrievers/identifierRetriever.js +66 -0
- package/dist/search/retrievers/identifierRetriever.js.map +1 -0
- package/dist/search/retrievers/structuralRetriever.d.ts +11 -0
- package/dist/search/retrievers/structuralRetriever.js +141 -0
- package/dist/search/retrievers/structuralRetriever.js.map +1 -0
- package/dist/search/types.d.ts +121 -0
- package/dist/search/types.js +11 -0
- package/dist/search/types.js.map +1 -0
- package/dist/tools/composites/apiGuard.d.ts +1 -0
- package/dist/tools/composites/apiGuard.js +194 -0
- package/dist/tools/composites/apiGuard.js.map +1 -0
- package/dist/tools/composites/explainError.js +3 -2
- package/dist/tools/composites/explainError.js.map +1 -1
- package/dist/tools/composites/findCode.d.ts +1 -0
- package/dist/tools/composites/findCode.js +68 -0
- package/dist/tools/composites/findCode.js.map +1 -0
- package/dist/tools/composites/findPattern.d.ts +5 -0
- package/dist/tools/composites/findPattern.js +41 -0
- package/dist/tools/composites/findPattern.js.map +1 -0
- package/dist/tools/composites/rootCauseTrace.d.ts +1 -0
- package/dist/tools/composites/rootCauseTrace.js +213 -0
- package/dist/tools/composites/rootCauseTrace.js.map +1 -0
- package/dist/tools/composites/semanticDiff.js +24 -77
- package/dist/tools/composites/semanticDiff.js.map +1 -1
- package/dist/tools/live/liveDiagnostics.js +3 -2
- package/dist/tools/live/liveDiagnostics.js.map +1 -1
- package/dist/tools/primitives/diagnostics.js +2 -2
- package/dist/tools/primitives/diagnostics.js.map +1 -1
- package/dist/tools/registry.d.ts +10 -2
- package/dist/tools/registry.js +7 -2
- package/dist/tools/registry.js.map +1 -1
- package/package.json +8 -4
- package/dist/tools/primitives/typeHierarchy.d.ts +0 -1
- package/dist/tools/primitives/typeHierarchy.js +0 -55
- package/dist/tools/primitives/typeHierarchy.js.map +0 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assess overall confidence of the search results.
|
|
3
|
+
* High = strong signals from multiple sources. Low = weak/generic matches.
|
|
4
|
+
*/
|
|
5
|
+
export function assessConfidence(ranked, ir, plan) {
|
|
6
|
+
if (ranked.length === 0)
|
|
7
|
+
return 'low';
|
|
8
|
+
const top = ranked[0];
|
|
9
|
+
const multiSource = top.sources.length > 1;
|
|
10
|
+
const hasStructural = top.sources.includes('structural');
|
|
11
|
+
const highScore = top.score >= 15;
|
|
12
|
+
const hasOverlap = top.evidence.some((e) => e.includes('overlap'));
|
|
13
|
+
if (multiSource && highScore)
|
|
14
|
+
return 'high';
|
|
15
|
+
if (hasStructural && top.score >= 10)
|
|
16
|
+
return 'high';
|
|
17
|
+
if (hasOverlap)
|
|
18
|
+
return 'high';
|
|
19
|
+
if (highScore)
|
|
20
|
+
return 'medium';
|
|
21
|
+
if (ir.modeConfidence === 'low')
|
|
22
|
+
return 'low';
|
|
23
|
+
return 'medium';
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=assessConfidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assessConfidence.js","sourceRoot":"","sources":["../../../src/search/ranking/assessConfidence.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAuB,EACvB,EAAW,EACX,IAAgB;IAEhB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAEtC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACtB,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3C,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;IAClC,MAAM,UAAU,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IAEnE,IAAI,WAAW,IAAI,SAAS;QAAE,OAAO,MAAM,CAAC;IAC5C,IAAI,aAAa,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE;QAAE,OAAO,MAAM,CAAC;IACpD,IAAI,UAAU;QAAE,OAAO,MAAM,CAAC;IAC9B,IAAI,SAAS;QAAE,OAAO,QAAQ,CAAC;IAC/B,IAAI,EAAE,CAAC,cAAc,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAE9C,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CodeCandidate } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Merge candidates from all retrievers, deduplicating by match identity.
|
|
4
|
+
* Overlapping candidates get a score boost.
|
|
5
|
+
*/
|
|
6
|
+
export declare function mergeCandidates(inputs: {
|
|
7
|
+
behavior: CodeCandidate[];
|
|
8
|
+
identifier: CodeCandidate[];
|
|
9
|
+
structural: CodeCandidate[];
|
|
10
|
+
}): CodeCandidate[];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { candidateKey } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Merge candidates from all retrievers, deduplicating by match identity.
|
|
4
|
+
* Overlapping candidates get a score boost.
|
|
5
|
+
*/
|
|
6
|
+
export function mergeCandidates(inputs) {
|
|
7
|
+
const merged = new Map();
|
|
8
|
+
// Add behavior candidates
|
|
9
|
+
for (const c of inputs.behavior) {
|
|
10
|
+
merged.set(candidateKey(c), { ...c });
|
|
11
|
+
}
|
|
12
|
+
// Merge identifier candidates — boost on overlap
|
|
13
|
+
for (const c of inputs.identifier) {
|
|
14
|
+
const key = candidateKey(c);
|
|
15
|
+
const existing = merged.get(key);
|
|
16
|
+
if (existing) {
|
|
17
|
+
existing.score += c.score + 3; // overlap bonus
|
|
18
|
+
existing.evidence.push(...c.evidence, 'multi-retriever-overlap');
|
|
19
|
+
for (const s of c.sources) {
|
|
20
|
+
if (!existing.sources.includes(s))
|
|
21
|
+
existing.sources.push(s);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
merged.set(key, { ...c });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Merge structural candidates — boost on overlap
|
|
29
|
+
for (const c of inputs.structural) {
|
|
30
|
+
const key = candidateKey(c);
|
|
31
|
+
const existing = merged.get(key);
|
|
32
|
+
if (existing) {
|
|
33
|
+
existing.score += c.score + 3;
|
|
34
|
+
existing.evidence.push(...c.evidence, 'structural-overlap');
|
|
35
|
+
for (const s of c.sources) {
|
|
36
|
+
if (!existing.sources.includes(s))
|
|
37
|
+
existing.sources.push(s);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
merged.set(key, { ...c });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return [...merged.values()];
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=mergeCandidates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mergeCandidates.js","sourceRoot":"","sources":["../../../src/search/ranking/mergeCandidates.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAI/B;IACC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAyB,CAAC;IAEhD,0BAA0B;IAC1B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,iDAAiD;IACjD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,gBAAgB;YAC/C,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,yBAAyB,CAAC,CAAC;YACjE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;gBAC1B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;oBAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;YAC9B,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;YAC5D,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;gBAC1B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;oBAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CodeCandidate, QueryIR, SearchPlan, SearchScope } from '../types.js';
|
|
2
|
+
import type { LspEngine } from '../../engine/LspEngine.js';
|
|
3
|
+
/**
|
|
4
|
+
* Rank candidates with mode-aware scoring + LSP enrichment.
|
|
5
|
+
* Applies penalties, enriches top candidates with hover signatures.
|
|
6
|
+
*/
|
|
7
|
+
export declare function rankCandidates(candidates: CodeCandidate[], ctx: {
|
|
8
|
+
ir: QueryIR;
|
|
9
|
+
plan: SearchPlan;
|
|
10
|
+
engine: LspEngine;
|
|
11
|
+
scope: SearchScope;
|
|
12
|
+
}): Promise<CodeCandidate[]>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { formatHover } from '../../format/markdown.js';
|
|
2
|
+
import { relativePath } from '../../engine/positions.js';
|
|
3
|
+
const TEST_PATTERN = /\.(spec|test|stories)\.(ts|tsx|js|jsx)$/;
|
|
4
|
+
const GENERATED_PATTERN = /\/(dist|es|build|generated|__generated__|\.cache)\//;
|
|
5
|
+
const DEMO_PATTERN = /\/(demo|example|storybook|stories|fixtures)\//;
|
|
6
|
+
/**
|
|
7
|
+
* Rank candidates with mode-aware scoring + LSP enrichment.
|
|
8
|
+
* Applies penalties, enriches top candidates with hover signatures.
|
|
9
|
+
*/
|
|
10
|
+
export async function rankCandidates(candidates, ctx) {
|
|
11
|
+
// Apply penalties
|
|
12
|
+
for (const c of candidates) {
|
|
13
|
+
if (TEST_PATTERN.test(c.filePath)) {
|
|
14
|
+
c.score -= 3;
|
|
15
|
+
c.evidence.push('penalty: test-file');
|
|
16
|
+
}
|
|
17
|
+
if (GENERATED_PATTERN.test(c.filePath)) {
|
|
18
|
+
c.score -= 10;
|
|
19
|
+
c.evidence.push('penalty: generated');
|
|
20
|
+
}
|
|
21
|
+
if (DEMO_PATTERN.test(c.filePath)) {
|
|
22
|
+
c.score -= 4;
|
|
23
|
+
c.evidence.push('penalty: demo');
|
|
24
|
+
}
|
|
25
|
+
if (c.filePath.endsWith('.d.ts')) {
|
|
26
|
+
c.score -= 6;
|
|
27
|
+
c.evidence.push('penalty: declaration-file');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Filter out negative scores
|
|
31
|
+
const filtered = candidates.filter((c) => c.score > 0);
|
|
32
|
+
// Sort by score
|
|
33
|
+
filtered.sort((a, b) => b.score - a.score);
|
|
34
|
+
// LSP enrichment for top candidates (use actual match position, not line 0)
|
|
35
|
+
const enrichLimit = Math.min(15, filtered.length);
|
|
36
|
+
for (let i = 0; i < enrichLimit; i++) {
|
|
37
|
+
const c = filtered[i];
|
|
38
|
+
try {
|
|
39
|
+
const { uri } = await ctx.engine.prepareFile(c.filePath);
|
|
40
|
+
const position = { line: c.line - 1, character: c.column ?? 0 };
|
|
41
|
+
const hover = await ctx.engine.request('textDocument/hover', { textDocument: { uri }, position }, 5000);
|
|
42
|
+
if (hover) {
|
|
43
|
+
c.signature = formatHover(hover).substring(0, 200);
|
|
44
|
+
if (!c.sources.includes('lsp'))
|
|
45
|
+
c.sources.push('lsp');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
c.evidence.push(`lsp-enrich-failed: ${err?.message ?? 'unknown'}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Relativize file paths
|
|
53
|
+
for (const c of filtered) {
|
|
54
|
+
c.filePath = relativePath(c.filePath, ctx.engine.workspaceRoot);
|
|
55
|
+
}
|
|
56
|
+
return filtered;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=rankCandidates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rankCandidates.js","sourceRoot":"","sources":["../../../src/search/ranking/rankCandidates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { QueryIR, SearchScope, WorkspaceIndex, CodeCandidate } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Retrieve declaration-oriented candidates based on behavior family matching.
|
|
4
|
+
* Uses declaration index + family classifier/expansion terms + file/symbol hints.
|
|
5
|
+
* Does NOT use exact identifier matching — that's the identifier retriever's job.
|
|
6
|
+
*/
|
|
7
|
+
export declare function retrieveBehaviorCandidates(ir: QueryIR, scope: SearchScope, index: WorkspaceIndex): CodeCandidate[];
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { BEHAVIOR_FAMILIES } from '../families/behaviorFamilies.js';
|
|
2
|
+
import { buildSnippetFromFile } from '../../analysis/ts/snippets.js';
|
|
3
|
+
/**
|
|
4
|
+
* Prefix-based partial match with minimum length guard.
|
|
5
|
+
* Prevents false positives like 'permission'.includes('is').
|
|
6
|
+
*/
|
|
7
|
+
function isStrongPartialMatch(a, b) {
|
|
8
|
+
if (a.length < 4 || b.length < 4)
|
|
9
|
+
return false;
|
|
10
|
+
return a.startsWith(b) || b.startsWith(a);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Retrieve declaration-oriented candidates based on behavior family matching.
|
|
14
|
+
* Uses declaration index + family classifier/expansion terms + file/symbol hints.
|
|
15
|
+
* Does NOT use exact identifier matching — that's the identifier retriever's job.
|
|
16
|
+
*/
|
|
17
|
+
export function retrieveBehaviorCandidates(ir, scope, index) {
|
|
18
|
+
const candidates = [];
|
|
19
|
+
const matchedFamilies = BEHAVIOR_FAMILIES.filter((f) => ir.familyScores[f.id] > 0);
|
|
20
|
+
if (matchedFamilies.length === 0 && ir.nlTokens.length === 0)
|
|
21
|
+
return [];
|
|
22
|
+
// Score each declaration against NL tokens + family hints
|
|
23
|
+
for (const decl of index.declarations) {
|
|
24
|
+
let score = 0;
|
|
25
|
+
const evidence = [];
|
|
26
|
+
// Family symbol hints
|
|
27
|
+
for (const family of matchedFamilies) {
|
|
28
|
+
for (const hint of family.symbolHints) {
|
|
29
|
+
for (const tok of decl.symbolTokens) {
|
|
30
|
+
if (tok === hint) {
|
|
31
|
+
score += 5;
|
|
32
|
+
evidence.push(`symbol-hint: ${hint}`);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
if (isStrongPartialMatch(tok, hint)) {
|
|
36
|
+
score += 2;
|
|
37
|
+
evidence.push(`symbol-partial: ${hint}~${tok}`);
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const hint of family.fileHints) {
|
|
43
|
+
for (const tok of decl.pathTokens) {
|
|
44
|
+
if (tok.includes(hint)) {
|
|
45
|
+
score += 3;
|
|
46
|
+
evidence.push(`file-hint: ${hint}`);
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// NL token matching against symbol tokens
|
|
53
|
+
for (const nlTok of ir.nlTokens) {
|
|
54
|
+
for (const symTok of decl.symbolTokens) {
|
|
55
|
+
if (symTok === nlTok) {
|
|
56
|
+
score += 4;
|
|
57
|
+
evidence.push(`nl-match: ${nlTok}`);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
if (isStrongPartialMatch(symTok, nlTok)) {
|
|
61
|
+
score += 2;
|
|
62
|
+
evidence.push(`nl-partial: ${nlTok}~${symTok}`);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Export bonus
|
|
68
|
+
if (decl.isExported && score > 0) {
|
|
69
|
+
score += 2;
|
|
70
|
+
evidence.push('exported');
|
|
71
|
+
}
|
|
72
|
+
if (score > 0) {
|
|
73
|
+
const { snippet, context } = buildSnippetFromFile(decl.filePath, decl.line, 1);
|
|
74
|
+
candidates.push({
|
|
75
|
+
candidateType: 'declaration',
|
|
76
|
+
filePath: decl.filePath,
|
|
77
|
+
line: decl.line,
|
|
78
|
+
column: decl.column,
|
|
79
|
+
symbol: decl.symbol,
|
|
80
|
+
kind: decl.kind,
|
|
81
|
+
snippet,
|
|
82
|
+
context,
|
|
83
|
+
score,
|
|
84
|
+
evidence,
|
|
85
|
+
sources: ['behavior'],
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return candidates.sort((a, b) => b.score - a.score);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=behaviorRetriever.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behaviorRetriever.js","sourceRoot":"","sources":["../../../src/search/retrievers/behaviorRetriever.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { QueryIR, SearchScope, WorkspaceIndex, CodeCandidate } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Retrieve usage-oriented candidates based on exact identifier matching.
|
|
4
|
+
* Uses usage index — call expressions, member calls, imports, JSX tags.
|
|
5
|
+
* This is the missing backend that makes useEffect, Promise.all queries work.
|
|
6
|
+
*/
|
|
7
|
+
export declare function retrieveIdentifierCandidates(ir: QueryIR, scope: SearchScope, index: WorkspaceIndex): CodeCandidate[];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { buildSnippetFromFile } from '../../analysis/ts/snippets.js';
|
|
2
|
+
/**
|
|
3
|
+
* Retrieve usage-oriented candidates based on exact identifier matching.
|
|
4
|
+
* Uses usage index — call expressions, member calls, imports, JSX tags.
|
|
5
|
+
* This is the missing backend that makes useEffect, Promise.all queries work.
|
|
6
|
+
*/
|
|
7
|
+
export function retrieveIdentifierCandidates(ir, scope, index) {
|
|
8
|
+
const candidates = [];
|
|
9
|
+
if (ir.exactIdentifiers.length === 0 && ir.dottedIdentifiers.length === 0)
|
|
10
|
+
return [];
|
|
11
|
+
for (const usage of index.usages) {
|
|
12
|
+
let score = 0;
|
|
13
|
+
const evidence = [];
|
|
14
|
+
// Exact identifier match
|
|
15
|
+
for (const id of ir.exactIdentifiers) {
|
|
16
|
+
if (usage.identifier === id || usage.normalizedIdentifier === id) {
|
|
17
|
+
score += 10;
|
|
18
|
+
evidence.push(`exact-identifier: ${id}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Dotted identifier match (Promise.all, React.useEffect)
|
|
22
|
+
for (const id of ir.dottedIdentifiers) {
|
|
23
|
+
if (usage.identifier === id) {
|
|
24
|
+
score += 10;
|
|
25
|
+
evidence.push(`dotted-identifier: ${id}`);
|
|
26
|
+
}
|
|
27
|
+
else if (usage.identifier.endsWith(id.split('.').pop() ?? '')) {
|
|
28
|
+
score += 5;
|
|
29
|
+
evidence.push(`dotted-partial: ${id}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (score === 0)
|
|
33
|
+
continue;
|
|
34
|
+
// Usage kind bonus
|
|
35
|
+
if (usage.kind === 'call' || usage.kind === 'member-call') {
|
|
36
|
+
score += 2;
|
|
37
|
+
evidence.push(`usage-kind: ${usage.kind}`);
|
|
38
|
+
}
|
|
39
|
+
else if (usage.kind === 'import') {
|
|
40
|
+
score += 1;
|
|
41
|
+
evidence.push('usage-kind: import');
|
|
42
|
+
}
|
|
43
|
+
// Enclosing symbol context
|
|
44
|
+
if (usage.enclosingSymbol) {
|
|
45
|
+
evidence.push(`enclosing: ${usage.enclosingSymbol}`);
|
|
46
|
+
}
|
|
47
|
+
const { snippet, context } = buildSnippetFromFile(usage.filePath, usage.line, 1);
|
|
48
|
+
candidates.push({
|
|
49
|
+
candidateType: 'usage',
|
|
50
|
+
filePath: usage.filePath,
|
|
51
|
+
line: usage.line,
|
|
52
|
+
column: usage.column,
|
|
53
|
+
matchedIdentifier: usage.identifier,
|
|
54
|
+
enclosingSymbol: usage.enclosingSymbol,
|
|
55
|
+
enclosingKind: usage.enclosingKind,
|
|
56
|
+
kind: 'usage',
|
|
57
|
+
snippet,
|
|
58
|
+
context,
|
|
59
|
+
score,
|
|
60
|
+
evidence,
|
|
61
|
+
sources: ['identifier'],
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return candidates.sort((a, b) => b.score - a.score);
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=identifierRetriever.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identifierRetriever.js","sourceRoot":"","sources":["../../../src/search/retrievers/identifierRetriever.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { QueryIR, SearchScope, WorkspaceIndex, CodeCandidate } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Retrieve candidates using structural predicate evaluation.
|
|
4
|
+
*
|
|
5
|
+
* Two-step design:
|
|
6
|
+
* Step 1: Locate candidate nodes (prefer usage sites of exact identifiers)
|
|
7
|
+
* Step 2: Evaluate structural predicates on each candidate node
|
|
8
|
+
*
|
|
9
|
+
* This is NOT recipe-only string patterns — it uses TS AST node evaluation.
|
|
10
|
+
*/
|
|
11
|
+
export declare function retrieveStructuralCandidates(ir: QueryIR, scope: SearchScope, index: WorkspaceIndex): CodeCandidate[];
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { parseSourceFile } from '../../analysis/ts/parseSourceFile.js';
|
|
2
|
+
import { evaluateStructuralPredicates } from '../../analysis/ts/structuralPredicates.js';
|
|
3
|
+
import { buildSnippetFromFile } from '../../analysis/ts/snippets.js';
|
|
4
|
+
import ts from 'typescript';
|
|
5
|
+
/**
|
|
6
|
+
* Retrieve candidates using structural predicate evaluation.
|
|
7
|
+
*
|
|
8
|
+
* Two-step design:
|
|
9
|
+
* Step 1: Locate candidate nodes (prefer usage sites of exact identifiers)
|
|
10
|
+
* Step 2: Evaluate structural predicates on each candidate node
|
|
11
|
+
*
|
|
12
|
+
* This is NOT recipe-only string patterns — it uses TS AST node evaluation.
|
|
13
|
+
*/
|
|
14
|
+
export function retrieveStructuralCandidates(ir, scope, index) {
|
|
15
|
+
if (ir.structuralPredicates.length === 0)
|
|
16
|
+
return [];
|
|
17
|
+
const candidates = [];
|
|
18
|
+
const maxFiles = 80;
|
|
19
|
+
let filesChecked = 0;
|
|
20
|
+
// Step 1: Determine which files to check
|
|
21
|
+
// If we have exact identifiers, only check files with matching usages
|
|
22
|
+
const targetFiles = new Set();
|
|
23
|
+
if (ir.exactIdentifiers.length > 0 || ir.dottedIdentifiers.length > 0) {
|
|
24
|
+
const allIds = [...ir.exactIdentifiers, ...ir.dottedIdentifiers];
|
|
25
|
+
for (const usage of index.usages) {
|
|
26
|
+
if (allIds.some((id) => usage.identifier === id || usage.normalizedIdentifier === id)) {
|
|
27
|
+
targetFiles.add(usage.filePath);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// No specific identifier — check files from behavior or all indexed files (capped)
|
|
33
|
+
for (const file of index.files.keys()) {
|
|
34
|
+
targetFiles.add(file);
|
|
35
|
+
if (targetFiles.size >= maxFiles)
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Step 2: For each target file, find nodes and evaluate predicates
|
|
40
|
+
for (const filePath of targetFiles) {
|
|
41
|
+
if (filesChecked >= maxFiles)
|
|
42
|
+
break;
|
|
43
|
+
filesChecked++;
|
|
44
|
+
const sf = parseSourceFile(filePath);
|
|
45
|
+
if (!sf)
|
|
46
|
+
continue;
|
|
47
|
+
// Find candidate nodes: call expressions matching our identifiers
|
|
48
|
+
const allIds = [...ir.exactIdentifiers, ...ir.dottedIdentifiers];
|
|
49
|
+
const nodes = findTargetCallNodes(sf, allIds);
|
|
50
|
+
for (const { node, identifier, line } of nodes) {
|
|
51
|
+
const { matched, evidence } = evaluateStructuralPredicates(sf, node, ir.structuralPredicates);
|
|
52
|
+
if (matched.length === 0)
|
|
53
|
+
continue;
|
|
54
|
+
const score = matched.length * 5 + (matched.length === ir.structuralPredicates.length ? 5 : 0);
|
|
55
|
+
const { snippet, context } = buildSnippetFromFile(filePath, line, 2);
|
|
56
|
+
// Find enclosing function/component name
|
|
57
|
+
const enclosing = findEnclosingDeclaration(node);
|
|
58
|
+
candidates.push({
|
|
59
|
+
candidateType: 'usage',
|
|
60
|
+
filePath,
|
|
61
|
+
line,
|
|
62
|
+
column: sf.getLineAndCharacterOfPosition(node.getStart(sf)).character,
|
|
63
|
+
matchedIdentifier: identifier,
|
|
64
|
+
enclosingSymbol: enclosing?.name,
|
|
65
|
+
enclosingKind: enclosing?.kind,
|
|
66
|
+
kind: 'usage',
|
|
67
|
+
snippet,
|
|
68
|
+
context,
|
|
69
|
+
score,
|
|
70
|
+
evidence: [
|
|
71
|
+
`structural-match: ${matched.join(', ')}`,
|
|
72
|
+
`predicates: ${matched.length}/${ir.structuralPredicates.length}`,
|
|
73
|
+
...evidence,
|
|
74
|
+
],
|
|
75
|
+
sources: ['structural'],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return candidates.sort((a, b) => b.score - a.score);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Find call expression nodes that match the target identifiers.
|
|
83
|
+
* For queries without identifiers, returns all top-level call expressions.
|
|
84
|
+
*/
|
|
85
|
+
function findTargetCallNodes(sf, identifiers) {
|
|
86
|
+
const nodes = [];
|
|
87
|
+
function visit(node) {
|
|
88
|
+
if (ts.isCallExpression(node)) {
|
|
89
|
+
const expr = node.expression;
|
|
90
|
+
let name = null;
|
|
91
|
+
if (ts.isIdentifier(expr)) {
|
|
92
|
+
name = expr.text;
|
|
93
|
+
}
|
|
94
|
+
else if (ts.isPropertyAccessExpression(expr)) {
|
|
95
|
+
name = getFullPropertyAccess(expr);
|
|
96
|
+
}
|
|
97
|
+
if (name) {
|
|
98
|
+
const matches = identifiers.length === 0 ||
|
|
99
|
+
identifiers.some((id) => name === id || name.endsWith(`.${id}`));
|
|
100
|
+
if (matches) {
|
|
101
|
+
const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
102
|
+
nodes.push({ node, identifier: name, line });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
ts.forEachChild(node, visit);
|
|
107
|
+
}
|
|
108
|
+
visit(sf);
|
|
109
|
+
return nodes;
|
|
110
|
+
}
|
|
111
|
+
function getFullPropertyAccess(node) {
|
|
112
|
+
const parts = [node.name.text];
|
|
113
|
+
let current = node.expression;
|
|
114
|
+
while (ts.isPropertyAccessExpression(current)) {
|
|
115
|
+
parts.unshift(current.name.text);
|
|
116
|
+
current = current.expression;
|
|
117
|
+
}
|
|
118
|
+
if (ts.isIdentifier(current))
|
|
119
|
+
parts.unshift(current.text);
|
|
120
|
+
return parts.join('.');
|
|
121
|
+
}
|
|
122
|
+
function findEnclosingDeclaration(node) {
|
|
123
|
+
let current = node.parent;
|
|
124
|
+
while (current) {
|
|
125
|
+
if (ts.isFunctionDeclaration(current) && current.name) {
|
|
126
|
+
return { name: current.name.text, kind: 'function' };
|
|
127
|
+
}
|
|
128
|
+
if (ts.isVariableDeclaration(current) && ts.isIdentifier(current.name)) {
|
|
129
|
+
return { name: current.name.text, kind: 'variable' };
|
|
130
|
+
}
|
|
131
|
+
if (ts.isMethodDeclaration(current) && ts.isIdentifier(current.name)) {
|
|
132
|
+
return { name: current.name.text, kind: 'method' };
|
|
133
|
+
}
|
|
134
|
+
if (ts.isClassDeclaration(current) && current.name) {
|
|
135
|
+
return { name: current.name.text, kind: 'class' };
|
|
136
|
+
}
|
|
137
|
+
current = current.parent;
|
|
138
|
+
}
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=structuralRetriever.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structuralRetriever.js","sourceRoot":"","sources":["../../../src/search/retrievers/structuralRetriever.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export type StructuralPredicate = 'conditional' | 'returns-function' | 'returns-cleanup' | 'no-cleanup' | 'has-try-catch' | 'no-try-catch' | 'switch-no-default' | 'await-in-loop' | 'inside-hook' | 'hook-callback';
|
|
2
|
+
export interface QueryIR {
|
|
3
|
+
raw: string;
|
|
4
|
+
/** Natural-language tokens (lowercased, stop-words removed) */
|
|
5
|
+
nlTokens: string[];
|
|
6
|
+
/** Multi-word phrases preserved from the query */
|
|
7
|
+
phrases: string[];
|
|
8
|
+
/** Exact identifiers: useEffect, AbortController, useMemo */
|
|
9
|
+
exactIdentifiers: string[];
|
|
10
|
+
/** Dotted identifiers: Promise.all, React.useEffect */
|
|
11
|
+
dottedIdentifiers: string[];
|
|
12
|
+
/** Code-oriented tokens that aren't exact identifiers: cleanup, callback */
|
|
13
|
+
codeTokens: string[];
|
|
14
|
+
/** Per-family relevance scores */
|
|
15
|
+
familyScores: Record<string, number>;
|
|
16
|
+
/** Structural predicates inferred from the query */
|
|
17
|
+
structuralPredicates: StructuralPredicate[];
|
|
18
|
+
/** Routing mode */
|
|
19
|
+
mode: 'behavior' | 'identifier' | 'structural' | 'mixed';
|
|
20
|
+
modeConfidence: 'high' | 'medium' | 'low';
|
|
21
|
+
routingReasons: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface SearchPlan {
|
|
24
|
+
mode: 'behavior' | 'identifier' | 'structural' | 'mixed';
|
|
25
|
+
retrievers: Array<'behavior' | 'identifier' | 'structural'>;
|
|
26
|
+
reasons: string[];
|
|
27
|
+
}
|
|
28
|
+
export interface SearchScope {
|
|
29
|
+
roots: string[];
|
|
30
|
+
filePaths?: string[];
|
|
31
|
+
includeTests: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface CodeCandidate {
|
|
34
|
+
candidateType: 'declaration' | 'usage' | 'pattern';
|
|
35
|
+
filePath: string;
|
|
36
|
+
line: number;
|
|
37
|
+
column?: number;
|
|
38
|
+
symbol?: string;
|
|
39
|
+
enclosingSymbol?: string;
|
|
40
|
+
enclosingKind?: string;
|
|
41
|
+
matchedIdentifier?: string;
|
|
42
|
+
kind?: 'function' | 'class' | 'method' | 'variable' | 'component' | 'file' | 'usage' | 'pattern';
|
|
43
|
+
signature?: string;
|
|
44
|
+
snippet?: string;
|
|
45
|
+
context?: string;
|
|
46
|
+
score: number;
|
|
47
|
+
confidence?: 'high' | 'medium' | 'low';
|
|
48
|
+
evidence: string[];
|
|
49
|
+
sources: Array<'behavior' | 'identifier' | 'structural' | 'lsp'>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Deduplication key for candidates.
|
|
53
|
+
* Uses match identity, not just symbol name.
|
|
54
|
+
*/
|
|
55
|
+
export declare function candidateKey(c: CodeCandidate): string;
|
|
56
|
+
export interface DeclarationIndexEntry {
|
|
57
|
+
symbol: string;
|
|
58
|
+
kind: string;
|
|
59
|
+
filePath: string;
|
|
60
|
+
line: number;
|
|
61
|
+
column: number;
|
|
62
|
+
isExported: boolean;
|
|
63
|
+
pathTokens: string[];
|
|
64
|
+
symbolTokens: string[];
|
|
65
|
+
}
|
|
66
|
+
export interface UsageIndexEntry {
|
|
67
|
+
identifier: string;
|
|
68
|
+
normalizedIdentifier: string;
|
|
69
|
+
kind: 'call' | 'member-call' | 'identifier' | 'import' | 'jsx-tag';
|
|
70
|
+
filePath: string;
|
|
71
|
+
line: number;
|
|
72
|
+
column: number;
|
|
73
|
+
enclosingSymbol?: string;
|
|
74
|
+
enclosingKind?: string;
|
|
75
|
+
pathTokens: string[];
|
|
76
|
+
}
|
|
77
|
+
export interface IndexedFile {
|
|
78
|
+
filePath: string;
|
|
79
|
+
mtimeMs: number;
|
|
80
|
+
declarations: DeclarationIndexEntry[];
|
|
81
|
+
usages: UsageIndexEntry[];
|
|
82
|
+
}
|
|
83
|
+
export interface WorkspaceIndex {
|
|
84
|
+
root: string;
|
|
85
|
+
builtAt: number;
|
|
86
|
+
files: Map<string, IndexedFile>;
|
|
87
|
+
declarations: DeclarationIndexEntry[];
|
|
88
|
+
usages: UsageIndexEntry[];
|
|
89
|
+
}
|
|
90
|
+
export interface FindCodeResult {
|
|
91
|
+
query: string;
|
|
92
|
+
ir: QueryIR;
|
|
93
|
+
plan: SearchPlan;
|
|
94
|
+
confidence: 'high' | 'medium' | 'low';
|
|
95
|
+
candidates: CodeCandidate[];
|
|
96
|
+
stats: {
|
|
97
|
+
filesIndexed: number;
|
|
98
|
+
declarationHits: number;
|
|
99
|
+
usageHits: number;
|
|
100
|
+
structuralHits: number;
|
|
101
|
+
lspEnriched: number;
|
|
102
|
+
elapsedMs: number;
|
|
103
|
+
partialResult: boolean;
|
|
104
|
+
};
|
|
105
|
+
warnings: string[];
|
|
106
|
+
}
|
|
107
|
+
export interface PatternMatch {
|
|
108
|
+
filePath: string;
|
|
109
|
+
line: number;
|
|
110
|
+
column?: number;
|
|
111
|
+
text: string;
|
|
112
|
+
context: string;
|
|
113
|
+
}
|
|
114
|
+
export interface FindPatternResult {
|
|
115
|
+
pattern: string;
|
|
116
|
+
language: 'typescript' | 'tsx' | 'javascript';
|
|
117
|
+
filesScanned: number;
|
|
118
|
+
matchCount: number;
|
|
119
|
+
matches: PatternMatch[];
|
|
120
|
+
warnings: string[];
|
|
121
|
+
}
|