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
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Type-aware code intelligence for AI agents — impact analysis, semantic diff, and context building via LSP.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**28 MCP tools** across 5 layers — from basic navigation to "what breaks if I change this?" in one call.
|
|
6
6
|
|
|
7
7
|
Currently supports **TypeScript and JavaScript** projects. The architecture supports other LSP servers — additional language support is planned.
|
|
8
8
|
|
|
@@ -78,7 +78,7 @@ Use npm source in `marketplace.json` for version pinning and built-in dependency
|
|
|
78
78
|
"source": {
|
|
79
79
|
"source": "npm",
|
|
80
80
|
"package": "lsp-intelligence",
|
|
81
|
-
"version": "0.
|
|
81
|
+
"version": "0.2.0"
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
```
|
|
@@ -142,15 +142,19 @@ Direct LSP wrappers. Every tool accepts **symbol names** — agents never need t
|
|
|
142
142
|
| `file_imports` | List all imports of a file. |
|
|
143
143
|
| `file_exports` | List a file's public API including re-exports. |
|
|
144
144
|
|
|
145
|
-
### Layer 2:
|
|
145
|
+
### Layer 2: Intelligence Tools (10 tools)
|
|
146
146
|
|
|
147
|
-
Combine
|
|
147
|
+
Combine LSP, AST, and Git substrates into high-level operations.
|
|
148
148
|
|
|
149
149
|
| Tool | Description |
|
|
150
150
|
|------|-------------|
|
|
151
|
+
| `api_guard` | Detect public API contract changes — export diffs, structural classification, consumer impact, semver summary. |
|
|
152
|
+
| `root_cause_trace` | Trace the root cause of a TypeScript error — find the originating declaration change, not just the symptom. |
|
|
153
|
+
| `find_code` | Unified code search: behavior discovery, identifier/API usage search, and structural queries. Routes automatically based on the query. |
|
|
154
|
+
| `find_pattern` | AST structural search — find code by pattern (e.g. `useEffect($$$)`, `try { $$$ } catch ($E) { $$$ }`). |
|
|
151
155
|
| `inspect_symbol` | Hover + definition + references in one call. Full context about any symbol. |
|
|
152
156
|
| `batch_query` | Look up multiple symbols at once. Saves round-trips when exploring. |
|
|
153
|
-
| `impact_trace` | Follow a symbol through type aliases and re-exports to find ALL transitive usages.
|
|
157
|
+
| `impact_trace` | Follow a symbol through type aliases and re-exports to find ALL transitive usages. |
|
|
154
158
|
| `semantic_diff` | Analyze git diff semantically: identify changed symbols and their blast radius. |
|
|
155
159
|
| `find_test_files` | Find all test/spec/stories files that reference a symbol. |
|
|
156
160
|
| `explain_error` | Turn a TypeScript error into actionable context: expected type, actual type, and fix suggestion. |
|
|
@@ -184,7 +188,8 @@ Post-edit verification.
|
|
|
184
188
|
│ Layer 3: Context Engine [read-only] │
|
|
185
189
|
│ gather_context, outline │
|
|
186
190
|
├─────────────────────────────────────────────────────────┤
|
|
187
|
-
│ Layer 2:
|
|
191
|
+
│ Layer 2: Intelligence Tools [read-only] │
|
|
192
|
+
│ api_guard, root_cause_trace, find_code, find_pattern, │
|
|
188
193
|
│ impact_trace, semantic_diff, inspect_symbol, │
|
|
189
194
|
│ batch_query, find_test_files, explain_error │
|
|
190
195
|
├─────────────────────────────────────────────────────────┤
|
|
@@ -239,7 +244,7 @@ Add to your `.mcp.json`:
|
|
|
239
244
|
"mcpServers": {
|
|
240
245
|
"lsp": {
|
|
241
246
|
"command": "npx",
|
|
242
|
-
"args": ["-y", "lsp-intelligence"],
|
|
247
|
+
"args": ["--registry", "https://registry.npmjs.org", "-y", "lsp-intelligence"],
|
|
243
248
|
"env": {
|
|
244
249
|
"LSP_WORKSPACE_ROOT": "${CLAUDE_PROJECT_DIR}"
|
|
245
250
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { SKIP_DIRS } from '../../engine/types.js';
|
|
4
|
+
const TEST_PATTERN = /\.(spec|test|stories)\.(ts|tsx|js|jsx)$/;
|
|
5
|
+
/**
|
|
6
|
+
* Collect files matching a language within a search scope.
|
|
7
|
+
*/
|
|
8
|
+
export function collectSearchFiles(scope, extensions, maxFiles) {
|
|
9
|
+
const files = [];
|
|
10
|
+
for (const root of scope.roots) {
|
|
11
|
+
walkDir(root, files, extensions, scope.includeTests, maxFiles, 0);
|
|
12
|
+
if (files.length >= maxFiles)
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
return files;
|
|
16
|
+
}
|
|
17
|
+
function walkDir(dir, files, extensions, includeTests, maxFiles, depth) {
|
|
18
|
+
if (depth > 8 || files.length >= maxFiles)
|
|
19
|
+
return;
|
|
20
|
+
try {
|
|
21
|
+
for (const entry of fs.readdirSync(dir)) {
|
|
22
|
+
if (SKIP_DIRS.has(entry))
|
|
23
|
+
continue;
|
|
24
|
+
const full = path.join(dir, entry);
|
|
25
|
+
const stat = fs.statSync(full);
|
|
26
|
+
if (stat.isDirectory()) {
|
|
27
|
+
walkDir(full, files, extensions, includeTests, maxFiles, depth + 1);
|
|
28
|
+
}
|
|
29
|
+
else if (extensions.some((e) => entry.endsWith(e)) && !entry.endsWith('.d.ts')) {
|
|
30
|
+
if (!includeTests && TEST_PATTERN.test(entry))
|
|
31
|
+
continue;
|
|
32
|
+
files.push(full);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch { }
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=collectSearchFiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collectSearchFiles.js","sourceRoot":"","sources":["../../../src/analysis/pattern/collectSearchFiles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,MAAM,YAAY,GAAG,yCAAyC,CAAC;AAE/D;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAkB,EAClB,UAAoB,EACpB,QAAgB;IAEhB,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,YAAY,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAClE,IAAI,KAAK,CAAC,MAAM,IAAI,QAAQ;YAAE,MAAM;IACtC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,OAAO,CACd,GAAW,EACX,KAAe,EACf,UAAoB,EACpB,YAAqB,EACrB,QAAgB,EAChB,KAAa;IAEb,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO;IAClD,IAAI,CAAC;QACH,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YACxC,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,SAAS;YACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACnC,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACvB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YACtE,CAAC;iBAAM,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBACjF,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;oBAAE,SAAS;gBACxD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SearchScope, PatternMatch } from '../../search/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Run an ast-grep pattern search across files in scope.
|
|
4
|
+
* This is the engine behind find_pattern. Structural retrievers may also use it.
|
|
5
|
+
*/
|
|
6
|
+
export declare function runPatternSearch(input: {
|
|
7
|
+
pattern: string;
|
|
8
|
+
language: 'typescript' | 'tsx' | 'javascript';
|
|
9
|
+
scope: SearchScope;
|
|
10
|
+
maxResults: number;
|
|
11
|
+
contextLines: number;
|
|
12
|
+
workspaceRoot: string;
|
|
13
|
+
}): {
|
|
14
|
+
filesScanned: number;
|
|
15
|
+
matches: PatternMatch[];
|
|
16
|
+
warnings: string[];
|
|
17
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import { parse, Lang } from '@ast-grep/napi';
|
|
3
|
+
import { collectSearchFiles } from './collectSearchFiles.js';
|
|
4
|
+
import { relativePath } from '../../engine/positions.js';
|
|
5
|
+
const LANG_MAP = {
|
|
6
|
+
typescript: Lang.TypeScript,
|
|
7
|
+
tsx: Lang.Tsx,
|
|
8
|
+
javascript: Lang.JavaScript,
|
|
9
|
+
};
|
|
10
|
+
const EXT_MAP = {
|
|
11
|
+
typescript: ['.ts'],
|
|
12
|
+
tsx: ['.tsx', '.ts'],
|
|
13
|
+
javascript: ['.js'],
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Run an ast-grep pattern search across files in scope.
|
|
17
|
+
* This is the engine behind find_pattern. Structural retrievers may also use it.
|
|
18
|
+
*/
|
|
19
|
+
export function runPatternSearch(input) {
|
|
20
|
+
const lang = LANG_MAP[input.language];
|
|
21
|
+
if (!lang)
|
|
22
|
+
return { filesScanned: 0, matches: [], warnings: [`Unsupported language: ${input.language}`] };
|
|
23
|
+
const extensions = EXT_MAP[input.language];
|
|
24
|
+
const files = collectSearchFiles(input.scope, extensions, 500);
|
|
25
|
+
const matches = [];
|
|
26
|
+
const warnings = [];
|
|
27
|
+
for (const file of files) {
|
|
28
|
+
if (matches.length >= input.maxResults)
|
|
29
|
+
break;
|
|
30
|
+
try {
|
|
31
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
32
|
+
const root = parse(lang, content).root();
|
|
33
|
+
const found = root.findAll(input.pattern);
|
|
34
|
+
for (const match of found) {
|
|
35
|
+
if (matches.length >= input.maxResults)
|
|
36
|
+
break;
|
|
37
|
+
const range = match.range();
|
|
38
|
+
const line = range.start.line + 1;
|
|
39
|
+
matches.push({
|
|
40
|
+
filePath: relativePath(file, input.workspaceRoot),
|
|
41
|
+
line,
|
|
42
|
+
column: range.start.column,
|
|
43
|
+
text: match.text().substring(0, 200),
|
|
44
|
+
context: getContextLines(content, range.start.line, input.contextLines),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
warnings.push(`Parse failed for ${relativePath(file, input.workspaceRoot)}: ${err instanceof Error ? err.message : String(err)}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { filesScanned: files.length, matches, warnings };
|
|
53
|
+
}
|
|
54
|
+
function getContextLines(content, line0, ctx) {
|
|
55
|
+
const lines = content.split('\n');
|
|
56
|
+
const start = Math.max(0, line0 - ctx);
|
|
57
|
+
const end = Math.min(lines.length - 1, line0 + ctx);
|
|
58
|
+
return lines
|
|
59
|
+
.slice(start, end + 1)
|
|
60
|
+
.map((l, i) => `${start + i + 1}| ${l}`)
|
|
61
|
+
.join('\n');
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=runPatternSearch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runPatternSearch.js","sourceRoot":"","sources":["../../../src/analysis/pattern/runPatternSearch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import type { DeclarationIndexEntry } from '../../search/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract all declarations from a TypeScript source file using the TS compiler API.
|
|
5
|
+
* Returns top-level and exported declarations with symbol tokens for searching.
|
|
6
|
+
*/
|
|
7
|
+
export declare function extractDeclarations(sf: ts.SourceFile): DeclarationIndexEntry[];
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Tokenize a symbol name: split camelCase, PascalCase, snake_case.
|
|
5
|
+
*/
|
|
6
|
+
function tokenize(name) {
|
|
7
|
+
return name
|
|
8
|
+
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
9
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
10
|
+
.map((t) => t.toLowerCase())
|
|
11
|
+
.filter((t) => t.length > 1);
|
|
12
|
+
}
|
|
13
|
+
function pathTokenize(filePath) {
|
|
14
|
+
const rel = path.basename(filePath, path.extname(filePath));
|
|
15
|
+
return tokenize(rel);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Extract all declarations from a TypeScript source file using the TS compiler API.
|
|
19
|
+
* Returns top-level and exported declarations with symbol tokens for searching.
|
|
20
|
+
*/
|
|
21
|
+
export function extractDeclarations(sf) {
|
|
22
|
+
const entries = [];
|
|
23
|
+
const filePath = sf.fileName;
|
|
24
|
+
const pathToks = pathTokenize(filePath);
|
|
25
|
+
function visit(node) {
|
|
26
|
+
// Function declarations
|
|
27
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
28
|
+
entries.push(makeEntry(node.name.text, 'function', node, sf, filePath, pathToks));
|
|
29
|
+
}
|
|
30
|
+
// Variable statements: export const/let/var
|
|
31
|
+
else if (ts.isVariableStatement(node)) {
|
|
32
|
+
const isExported = hasExportModifier(node);
|
|
33
|
+
for (const decl of node.declarationList.declarations) {
|
|
34
|
+
if (ts.isIdentifier(decl.name)) {
|
|
35
|
+
const kind = decl.initializer && (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))
|
|
36
|
+
? 'function' : 'variable';
|
|
37
|
+
entries.push({
|
|
38
|
+
symbol: decl.name.text,
|
|
39
|
+
kind,
|
|
40
|
+
filePath,
|
|
41
|
+
line: sf.getLineAndCharacterOfPosition(decl.getStart(sf)).line + 1,
|
|
42
|
+
column: sf.getLineAndCharacterOfPosition(decl.getStart(sf)).character,
|
|
43
|
+
isExported,
|
|
44
|
+
pathTokens: pathToks,
|
|
45
|
+
symbolTokens: tokenize(decl.name.text),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Class declarations
|
|
51
|
+
else if (ts.isClassDeclaration(node) && node.name) {
|
|
52
|
+
entries.push(makeEntry(node.name.text, 'class', node, sf, filePath, pathToks));
|
|
53
|
+
}
|
|
54
|
+
// Interface declarations
|
|
55
|
+
else if (ts.isInterfaceDeclaration(node)) {
|
|
56
|
+
entries.push(makeEntry(node.name.text, 'interface', node, sf, filePath, pathToks));
|
|
57
|
+
}
|
|
58
|
+
// Type alias declarations
|
|
59
|
+
else if (ts.isTypeAliasDeclaration(node)) {
|
|
60
|
+
entries.push(makeEntry(node.name.text, 'type', node, sf, filePath, pathToks));
|
|
61
|
+
}
|
|
62
|
+
// Enum declarations
|
|
63
|
+
else if (ts.isEnumDeclaration(node)) {
|
|
64
|
+
entries.push(makeEntry(node.name.text, 'enum', node, sf, filePath, pathToks));
|
|
65
|
+
}
|
|
66
|
+
// Only visit top-level children
|
|
67
|
+
if (node === sf) {
|
|
68
|
+
ts.forEachChild(node, visit);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
visit(sf);
|
|
72
|
+
return entries;
|
|
73
|
+
}
|
|
74
|
+
function makeEntry(name, kind, node, sf, filePath, pathToks) {
|
|
75
|
+
const pos = sf.getLineAndCharacterOfPosition(node.getStart(sf));
|
|
76
|
+
return {
|
|
77
|
+
symbol: name,
|
|
78
|
+
kind,
|
|
79
|
+
filePath,
|
|
80
|
+
line: pos.line + 1,
|
|
81
|
+
column: pos.character,
|
|
82
|
+
isExported: hasExportModifier(node),
|
|
83
|
+
pathTokens: pathToks,
|
|
84
|
+
symbolTokens: tokenize(name),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function hasExportModifier(node) {
|
|
88
|
+
if (!ts.canHaveModifiers(node))
|
|
89
|
+
return false;
|
|
90
|
+
const mods = ts.getModifiers(node);
|
|
91
|
+
return mods?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=extractDeclarations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractDeclarations.js","sourceRoot":"","sources":["../../../src/analysis/ts/extractDeclarations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import type { UsageIndexEntry } from '../../search/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract all identifier usage sites from a TypeScript source file.
|
|
5
|
+
* Indexes: call expressions, member calls, import specifiers, JSX tags.
|
|
6
|
+
*/
|
|
7
|
+
export declare function extractUsages(sf: ts.SourceFile): UsageIndexEntry[];
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
function pathTokenize(filePath) {
|
|
4
|
+
return path.basename(filePath, path.extname(filePath))
|
|
5
|
+
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
6
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
7
|
+
.map((t) => t.toLowerCase())
|
|
8
|
+
.filter((t) => t.length > 1);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Extract all identifier usage sites from a TypeScript source file.
|
|
12
|
+
* Indexes: call expressions, member calls, import specifiers, JSX tags.
|
|
13
|
+
*/
|
|
14
|
+
export function extractUsages(sf) {
|
|
15
|
+
const entries = [];
|
|
16
|
+
const filePath = sf.fileName;
|
|
17
|
+
const pathToks = pathTokenize(filePath);
|
|
18
|
+
// Track enclosing symbol for context
|
|
19
|
+
let enclosingSymbol;
|
|
20
|
+
let enclosingKind;
|
|
21
|
+
function visit(node) {
|
|
22
|
+
// Save enclosing context so it restores correctly on recursion unwind
|
|
23
|
+
const prevSymbol = enclosingSymbol;
|
|
24
|
+
const prevKind = enclosingKind;
|
|
25
|
+
// Track enclosing function/class/method for context
|
|
26
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
27
|
+
enclosingSymbol = node.name.text;
|
|
28
|
+
enclosingKind = 'function';
|
|
29
|
+
}
|
|
30
|
+
else if (ts.isVariableStatement(node)) {
|
|
31
|
+
for (const decl of node.declarationList.declarations) {
|
|
32
|
+
if (ts.isIdentifier(decl.name) && decl.initializer &&
|
|
33
|
+
(ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
|
|
34
|
+
enclosingSymbol = decl.name.text;
|
|
35
|
+
enclosingKind = 'function';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (ts.isClassDeclaration(node) && node.name) {
|
|
40
|
+
enclosingSymbol = node.name.text;
|
|
41
|
+
enclosingKind = 'class';
|
|
42
|
+
}
|
|
43
|
+
else if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
44
|
+
enclosingSymbol = node.name.text;
|
|
45
|
+
enclosingKind = 'method';
|
|
46
|
+
}
|
|
47
|
+
// Call expressions: foo(), bar.baz()
|
|
48
|
+
if (ts.isCallExpression(node)) {
|
|
49
|
+
const expr = node.expression;
|
|
50
|
+
// Simple call: useEffect(...)
|
|
51
|
+
if (ts.isIdentifier(expr)) {
|
|
52
|
+
entries.push(makeUsage(expr.text, expr.text, 'call', node, sf, filePath, pathToks, enclosingSymbol, enclosingKind));
|
|
53
|
+
}
|
|
54
|
+
// Member call: Promise.all(...), sdk.Items.get(...)
|
|
55
|
+
else if (ts.isPropertyAccessExpression(expr)) {
|
|
56
|
+
const fullName = getPropertyAccessText(expr);
|
|
57
|
+
const leafName = expr.name.text;
|
|
58
|
+
entries.push(makeUsage(fullName, leafName, 'member-call', node, sf, filePath, pathToks, enclosingSymbol, enclosingKind));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Import declarations: import { X } from "module"
|
|
62
|
+
if (ts.isImportDeclaration(node) && node.importClause) {
|
|
63
|
+
const clause = node.importClause;
|
|
64
|
+
// Default import
|
|
65
|
+
if (clause.name) {
|
|
66
|
+
entries.push(makeUsage(clause.name.text, clause.name.text, 'import', clause.name, sf, filePath, pathToks, undefined, undefined));
|
|
67
|
+
}
|
|
68
|
+
// Named imports: { A, B }
|
|
69
|
+
if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
|
|
70
|
+
for (const spec of clause.namedBindings.elements) {
|
|
71
|
+
entries.push(makeUsage(spec.name.text, spec.name.text, 'import', spec, sf, filePath, pathToks, undefined, undefined));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Namespace import: * as X
|
|
75
|
+
if (clause.namedBindings && ts.isNamespaceImport(clause.namedBindings)) {
|
|
76
|
+
entries.push(makeUsage(clause.namedBindings.name.text, clause.namedBindings.name.text, 'import', clause.namedBindings, sf, filePath, pathToks, undefined, undefined));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// JSX elements: <Component ... />
|
|
80
|
+
if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
81
|
+
const tagName = node.tagName;
|
|
82
|
+
if (ts.isIdentifier(tagName) && /^[A-Z]/.test(tagName.text)) {
|
|
83
|
+
entries.push(makeUsage(tagName.text, tagName.text, 'jsx-tag', node, sf, filePath, pathToks, enclosingSymbol, enclosingKind));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
ts.forEachChild(node, visit);
|
|
87
|
+
// Restore enclosing context on unwind
|
|
88
|
+
enclosingSymbol = prevSymbol;
|
|
89
|
+
enclosingKind = prevKind;
|
|
90
|
+
}
|
|
91
|
+
visit(sf);
|
|
92
|
+
return entries;
|
|
93
|
+
}
|
|
94
|
+
function makeUsage(identifier, normalizedIdentifier, kind, node, sf, filePath, pathToks, enclosingSymbol, enclosingKind) {
|
|
95
|
+
const pos = sf.getLineAndCharacterOfPosition(node.getStart(sf));
|
|
96
|
+
return {
|
|
97
|
+
identifier,
|
|
98
|
+
normalizedIdentifier,
|
|
99
|
+
kind,
|
|
100
|
+
filePath,
|
|
101
|
+
line: pos.line + 1,
|
|
102
|
+
column: pos.character,
|
|
103
|
+
enclosingSymbol,
|
|
104
|
+
enclosingKind,
|
|
105
|
+
pathTokens: pathToks,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function getPropertyAccessText(node) {
|
|
109
|
+
const parts = [node.name.text];
|
|
110
|
+
let current = node.expression;
|
|
111
|
+
while (ts.isPropertyAccessExpression(current)) {
|
|
112
|
+
parts.unshift(current.name.text);
|
|
113
|
+
current = current.expression;
|
|
114
|
+
}
|
|
115
|
+
if (ts.isIdentifier(current)) {
|
|
116
|
+
parts.unshift(current.text);
|
|
117
|
+
}
|
|
118
|
+
return parts.join('.');
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=extractUsages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractUsages.js","sourceRoot":"","sources":["../../../src/analysis/ts/extractUsages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Parse a TypeScript/TSX file into a ts.SourceFile using the TypeScript compiler API.
|
|
4
|
+
* Returns null if the file doesn't exist or can't be parsed.
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseSourceFile(filePath: string): ts.SourceFile | null;
|
|
7
|
+
/**
|
|
8
|
+
* Parse source content directly (for base-version comparison).
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseSourceContent(content: string, fileName: string): ts.SourceFile;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
/**
|
|
4
|
+
* Parse a TypeScript/TSX file into a ts.SourceFile using the TypeScript compiler API.
|
|
5
|
+
* Returns null if the file doesn't exist or can't be parsed.
|
|
6
|
+
*/
|
|
7
|
+
export function parseSourceFile(filePath) {
|
|
8
|
+
try {
|
|
9
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
10
|
+
const scriptKind = filePath.endsWith('.tsx') ? ts.ScriptKind.TSX
|
|
11
|
+
: filePath.endsWith('.jsx') ? ts.ScriptKind.JSX
|
|
12
|
+
: ts.ScriptKind.TS;
|
|
13
|
+
return ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, scriptKind);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse source content directly (for base-version comparison).
|
|
21
|
+
*/
|
|
22
|
+
export function parseSourceContent(content, fileName) {
|
|
23
|
+
const scriptKind = fileName.endsWith('.tsx') ? ts.ScriptKind.TSX
|
|
24
|
+
: fileName.endsWith('.jsx') ? ts.ScriptKind.JSX
|
|
25
|
+
: ts.ScriptKind.TS;
|
|
26
|
+
return ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true, scriptKind);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=parseSourceFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseSourceFile.js","sourceRoot":"","sources":["../../../src/analysis/ts/parseSourceFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG;YAC9D,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG;gBAC/C,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAC1F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,QAAgB;IAClE,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG;QAC9D,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG;YAC/C,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;IACrB,OAAO,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;AAC1F,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a code snippet around a specific line, with optional context.
|
|
3
|
+
*/
|
|
4
|
+
export declare function buildSnippet(sourceText: string, line: number, column?: number, contextLines?: number): {
|
|
5
|
+
snippet: string;
|
|
6
|
+
context: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Build a snippet from a file path + line.
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildSnippetFromFile(filePath: string, line: number, contextLines?: number): {
|
|
12
|
+
snippet: string;
|
|
13
|
+
context: string;
|
|
14
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
/**
|
|
3
|
+
* Build a code snippet around a specific line, with optional context.
|
|
4
|
+
*/
|
|
5
|
+
export function buildSnippet(sourceText, line, column, contextLines = 1) {
|
|
6
|
+
const lines = sourceText.split('\n');
|
|
7
|
+
const line0 = line - 1; // Convert 1-indexed to 0-indexed
|
|
8
|
+
const start = Math.max(0, line0 - contextLines);
|
|
9
|
+
const end = Math.min(lines.length - 1, line0 + contextLines);
|
|
10
|
+
const snippet = lines[line0]?.trim() ?? '';
|
|
11
|
+
const context = lines
|
|
12
|
+
.slice(start, end + 1)
|
|
13
|
+
.map((l, i) => `${start + i + 1}| ${l}`)
|
|
14
|
+
.join('\n');
|
|
15
|
+
return { snippet, context };
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Build a snippet from a file path + line.
|
|
19
|
+
*/
|
|
20
|
+
export function buildSnippetFromFile(filePath, line, contextLines = 1) {
|
|
21
|
+
try {
|
|
22
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
23
|
+
return buildSnippet(content, line, undefined, contextLines);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return { snippet: '', context: '' };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=snippets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snippets.js","sourceRoot":"","sources":["../../../src/analysis/ts/snippets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,UAAkB,EAClB,IAAY,EACZ,MAAe,EACf,eAAuB,CAAC;IAExB,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,iCAAiC;IACzD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,YAAY,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,YAAY,CAAC,CAAC;IAE7D,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,KAAK;SAClB,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC;SACrB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;SACvC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,IAAY,EACZ,eAAuB,CAAC;IAExB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,OAAO,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACtC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import type { StructuralPredicate } from '../../search/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Evaluate structural predicates on a TS AST node.
|
|
5
|
+
* Returns which predicates matched and evidence strings.
|
|
6
|
+
*/
|
|
7
|
+
export declare function evaluateStructuralPredicates(sf: ts.SourceFile, node: ts.Node, predicates: StructuralPredicate[]): {
|
|
8
|
+
matched: StructuralPredicate[];
|
|
9
|
+
evidence: string[];
|
|
10
|
+
};
|