lsp-intelligence 0.2.1 → 0.3.2
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/.claude-plugin/marketplace.json +18 -0
- package/.claude-plugin/plugin.json +11 -0
- package/CLAUDE.md +75 -0
- package/README.md +15 -38
- package/dist/adapters/express/index.d.ts +9 -0
- package/dist/adapters/express/index.js +46 -0
- package/dist/adapters/express/index.js.map +1 -0
- package/dist/adapters/next/index.d.ts +10 -0
- package/dist/adapters/next/index.js +67 -0
- package/dist/adapters/next/index.js.map +1 -0
- package/dist/adapters/react/index.d.ts +11 -0
- package/dist/adapters/react/index.js +133 -0
- package/dist/adapters/react/index.js.map +1 -0
- package/dist/adapters/registry.d.ts +22 -0
- package/dist/adapters/registry.js +101 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/adapters/types.d.ts +97 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/analysis/ts/applyVirtualEdit.d.ts +27 -0
- package/dist/analysis/ts/applyVirtualEdit.js +235 -0
- package/dist/analysis/ts/applyVirtualEdit.js.map +1 -0
- package/dist/analysis/ts/changeRecipes.d.ts +52 -0
- package/dist/analysis/ts/changeRecipes.js +14 -0
- package/dist/analysis/ts/changeRecipes.js.map +1 -0
- package/dist/analysis/ts/compatibility.d.ts +54 -0
- package/dist/analysis/ts/compatibility.js +113 -0
- package/dist/analysis/ts/compatibility.js.map +1 -0
- package/dist/analysis/ts/diffDeclarationShape.d.ts +26 -0
- package/dist/analysis/ts/diffDeclarationShape.js +114 -0
- package/dist/analysis/ts/diffDeclarationShape.js.map +1 -0
- package/dist/analysis/ts/exhaustiveness.d.ts +49 -0
- package/dist/analysis/ts/exhaustiveness.js +158 -0
- package/dist/analysis/ts/exhaustiveness.js.map +1 -0
- package/dist/analysis/ts/extractDeclarationShape.d.ts +30 -0
- package/dist/analysis/ts/extractDeclarationShape.js +127 -0
- package/dist/analysis/ts/extractDeclarationShape.js.map +1 -0
- package/dist/analysis/ts/extractExports.d.ts +19 -0
- package/dist/analysis/ts/extractExports.js +178 -0
- package/dist/analysis/ts/extractExports.js.map +1 -0
- package/dist/analysis/ts/extractRoutes.d.ts +12 -0
- package/dist/analysis/ts/extractRoutes.js +165 -0
- package/dist/analysis/ts/extractRoutes.js.map +1 -0
- package/dist/analysis/ts/parseSourceFile.d.ts +5 -1
- package/dist/analysis/ts/parseSourceFile.js +6 -2
- package/dist/analysis/ts/parseSourceFile.js.map +1 -1
- package/dist/analysis/ts/program/CheckerQueries.d.ts +56 -0
- package/dist/analysis/ts/program/CheckerQueries.js +187 -0
- package/dist/analysis/ts/program/CheckerQueries.js.map +1 -0
- package/dist/analysis/ts/program/ProgramManager.d.ts +27 -0
- package/dist/analysis/ts/program/ProgramManager.js +147 -0
- package/dist/analysis/ts/program/ProgramManager.js.map +1 -0
- package/dist/analysis/ts/program/TypeFacts.d.ts +58 -0
- package/dist/analysis/ts/program/TypeFacts.js +68 -0
- package/dist/analysis/ts/program/TypeFacts.js.map +1 -0
- package/dist/analysis/ts/typeState.d.ts +46 -0
- package/dist/analysis/ts/typeState.js +108 -0
- package/dist/analysis/ts/typeState.js.map +1 -0
- package/dist/ast/diffDeclarationShapes.js +25 -11
- package/dist/ast/diffDeclarationShapes.js.map +1 -1
- package/dist/ast/extractExportDeclarations.js +8 -3
- package/dist/ast/extractExportDeclarations.js.map +1 -1
- package/dist/cache/CacheSchema.d.ts +30 -0
- package/dist/cache/CacheSchema.js +9 -0
- package/dist/cache/CacheSchema.js.map +1 -0
- package/dist/cache/CacheStore.d.ts +22 -0
- package/dist/cache/CacheStore.js +111 -0
- package/dist/cache/CacheStore.js.map +1 -0
- package/dist/cache/SemanticCache.d.ts +38 -0
- package/dist/cache/SemanticCache.js +87 -0
- package/dist/cache/SemanticCache.js.map +1 -0
- package/dist/cache/SnapshotFingerprint.d.ts +17 -0
- package/dist/cache/SnapshotFingerprint.js +14 -0
- package/dist/cache/SnapshotFingerprint.js.map +1 -0
- package/dist/engine/DocumentManager.d.ts +16 -0
- package/dist/engine/DocumentManager.js +32 -0
- package/dist/engine/DocumentManager.js.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/search/adapters/http.d.ts +9 -3
- package/dist/search/adapters/http.js +7 -52
- package/dist/search/adapters/http.js.map +1 -1
- package/dist/search/adapters/react.d.ts +8 -8
- package/dist/search/adapters/react.js +3 -88
- package/dist/search/adapters/react.js.map +1 -1
- package/dist/search/adapters/registry.d.ts +7 -4
- package/dist/search/adapters/registry.js +7 -17
- package/dist/search/adapters/registry.js.map +1 -1
- package/dist/search/expand/graphExpansion.js +47 -14
- package/dist/search/expand/graphExpansion.js.map +1 -1
- package/dist/search/index/declarationIndex.d.ts +3 -1
- package/dist/search/index/declarationIndex.js +4 -2
- package/dist/search/index/declarationIndex.js.map +1 -1
- package/dist/search/index/routeIndex.d.ts +6 -0
- package/dist/search/index/routeIndex.js +19 -0
- package/dist/search/index/routeIndex.js.map +1 -0
- package/dist/search/index/usageIndex.d.ts +3 -1
- package/dist/search/index/usageIndex.js +4 -2
- package/dist/search/index/usageIndex.js.map +1 -1
- package/dist/search/index/workspaceIndex.d.ts +7 -1
- package/dist/search/index/workspaceIndex.js +54 -14
- package/dist/search/index/workspaceIndex.js.map +1 -1
- package/dist/search/query/compileEffectiveSearchSpec.js +9 -0
- package/dist/search/query/compileEffectiveSearchSpec.js.map +1 -1
- package/dist/search/query/parseQuery.js +5 -1
- package/dist/search/query/parseQuery.js.map +1 -1
- package/dist/search/query/planQuery.js +14 -4
- package/dist/search/query/planQuery.js.map +1 -1
- package/dist/search/ranking/mergeCandidates.d.ts +1 -0
- package/dist/search/ranking/mergeCandidates.js +16 -0
- package/dist/search/ranking/mergeCandidates.js.map +1 -1
- package/dist/search/retrievers/routeRetriever.d.ts +7 -0
- package/dist/search/retrievers/routeRetriever.js +64 -0
- package/dist/search/retrievers/routeRetriever.js.map +1 -0
- package/dist/search/types.d.ts +16 -4
- package/dist/session/OverlayStore.d.ts +15 -0
- package/dist/session/OverlayStore.js +46 -0
- package/dist/session/OverlayStore.js.map +1 -0
- package/dist/session/SnapshotResolver.d.ts +31 -0
- package/dist/session/SnapshotResolver.js +50 -0
- package/dist/session/SnapshotResolver.js.map +1 -0
- package/dist/session/WorkspaceSnapshot.d.ts +21 -0
- package/dist/session/WorkspaceSnapshot.js +2 -0
- package/dist/session/WorkspaceSnapshot.js.map +1 -0
- package/dist/tools/composites/apiGuard.d.ts +4 -0
- package/dist/tools/composites/apiGuard.js +158 -24
- package/dist/tools/composites/apiGuard.js.map +1 -1
- package/dist/tools/composites/findCode.js +12 -2
- package/dist/tools/composites/findCode.js.map +1 -1
- package/dist/tools/composites/rootCauseTrace.js +89 -13
- package/dist/tools/composites/rootCauseTrace.js.map +1 -1
- package/dist/workflows/simulateChange.d.ts +44 -0
- package/dist/workflows/simulateChange.js +194 -0
- package/dist/workflows/simulateChange.js.map +1 -0
- package/dist/workflows/verifyChangeSet.d.ts +58 -0
- package/dist/workflows/verifyChangeSet.js +300 -0
- package/dist/workflows/verifyChangeSet.js.map +1 -0
- package/hooks/hooks.json +25 -0
- package/hooks/post-edit-check.sh +23 -0
- package/package.json +20 -4
- package/scripts/launch.mjs +29 -0
- package/skills/api-check/SKILL.md +34 -0
- package/skills/check/SKILL.md +25 -0
- package/skills/context/SKILL.md +24 -0
- package/skills/diff/SKILL.md +27 -0
- package/skills/find/SKILL.md +63 -0
- package/skills/impact/SKILL.md +21 -0
- package/skills/verify/SKILL.md +54 -0
- package/skills/why/SKILL.md +31 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Extract all exports from a TypeScript/JavaScript source file using the TS AST.
|
|
4
|
+
* Supports ESM (export function, export const, export { }, export * from, export default)
|
|
5
|
+
* and basic CJS (module.exports, exports.foo).
|
|
6
|
+
*/
|
|
7
|
+
export function extractExports(sf) {
|
|
8
|
+
const exports = [];
|
|
9
|
+
const filePath = sf.fileName;
|
|
10
|
+
function visit(node) {
|
|
11
|
+
// ESM: export function foo() {}
|
|
12
|
+
if (ts.isFunctionDeclaration(node) && hasExportModifier(node) && node.name) {
|
|
13
|
+
exports.push({
|
|
14
|
+
name: node.name.text,
|
|
15
|
+
exportedAs: [node.name.text],
|
|
16
|
+
kind: 'function',
|
|
17
|
+
filePath,
|
|
18
|
+
line: lineOf(node, sf),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
// ESM: export class Foo {}
|
|
22
|
+
if (ts.isClassDeclaration(node) && hasExportModifier(node) && node.name) {
|
|
23
|
+
exports.push({
|
|
24
|
+
name: node.name.text,
|
|
25
|
+
exportedAs: [node.name.text],
|
|
26
|
+
kind: 'class',
|
|
27
|
+
filePath,
|
|
28
|
+
line: lineOf(node, sf),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
// ESM: export interface Foo {}
|
|
32
|
+
if (ts.isInterfaceDeclaration(node) && hasExportModifier(node)) {
|
|
33
|
+
exports.push({
|
|
34
|
+
name: node.name.text,
|
|
35
|
+
exportedAs: [node.name.text],
|
|
36
|
+
kind: 'interface',
|
|
37
|
+
filePath,
|
|
38
|
+
line: lineOf(node, sf),
|
|
39
|
+
isTypeOnly: true,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// ESM: export type Foo = ...
|
|
43
|
+
if (ts.isTypeAliasDeclaration(node) && hasExportModifier(node)) {
|
|
44
|
+
exports.push({
|
|
45
|
+
name: node.name.text,
|
|
46
|
+
exportedAs: [node.name.text],
|
|
47
|
+
kind: 'type',
|
|
48
|
+
filePath,
|
|
49
|
+
line: lineOf(node, sf),
|
|
50
|
+
isTypeOnly: true,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// ESM: export enum Foo {}
|
|
54
|
+
if (ts.isEnumDeclaration(node) && hasExportModifier(node)) {
|
|
55
|
+
exports.push({
|
|
56
|
+
name: node.name.text,
|
|
57
|
+
exportedAs: [node.name.text],
|
|
58
|
+
kind: 'enum',
|
|
59
|
+
filePath,
|
|
60
|
+
line: lineOf(node, sf),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
// ESM: export const foo = ..., export let bar = ...
|
|
64
|
+
if (ts.isVariableStatement(node) && hasExportModifier(node)) {
|
|
65
|
+
for (const decl of node.declarationList.declarations) {
|
|
66
|
+
if (ts.isIdentifier(decl.name)) {
|
|
67
|
+
exports.push({
|
|
68
|
+
name: decl.name.text,
|
|
69
|
+
exportedAs: [decl.name.text],
|
|
70
|
+
kind: node.declarationList.flags & ts.NodeFlags.Const ? 'const' : 'var',
|
|
71
|
+
filePath,
|
|
72
|
+
line: lineOf(node, sf),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// ESM: export default ...
|
|
78
|
+
if (ts.isExportAssignment(node) && !node.isExportEquals) {
|
|
79
|
+
const name = ts.isIdentifier(node.expression) ? node.expression.text : 'default';
|
|
80
|
+
exports.push({
|
|
81
|
+
name,
|
|
82
|
+
exportedAs: ['default'],
|
|
83
|
+
kind: 'default',
|
|
84
|
+
filePath,
|
|
85
|
+
line: lineOf(node, sf),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// ESM: export { foo, bar as baz }
|
|
89
|
+
if (ts.isExportDeclaration(node)) {
|
|
90
|
+
const moduleSpec = node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)
|
|
91
|
+
? node.moduleSpecifier.text : undefined;
|
|
92
|
+
if (node.exportClause && ts.isNamedExports(node.exportClause)) {
|
|
93
|
+
for (const spec of node.exportClause.elements) {
|
|
94
|
+
const localName = (spec.propertyName ?? spec.name).text;
|
|
95
|
+
const exportedName = spec.name.text;
|
|
96
|
+
exports.push({
|
|
97
|
+
name: localName,
|
|
98
|
+
exportedAs: [exportedName],
|
|
99
|
+
kind: moduleSpec ? 'reexport' : 'unknown',
|
|
100
|
+
filePath,
|
|
101
|
+
line: lineOf(spec, sf),
|
|
102
|
+
isTypeOnly: node.isTypeOnly || spec.isTypeOnly,
|
|
103
|
+
moduleSpecifier: moduleSpec,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (!node.exportClause && moduleSpec) {
|
|
108
|
+
// export * from '...'
|
|
109
|
+
exports.push({
|
|
110
|
+
name: '*',
|
|
111
|
+
exportedAs: ['*'],
|
|
112
|
+
kind: 'reexport',
|
|
113
|
+
filePath,
|
|
114
|
+
line: lineOf(node, sf),
|
|
115
|
+
moduleSpecifier: moduleSpec,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// CJS: module.exports = ... or module.exports.foo = ...
|
|
120
|
+
if (ts.isExpressionStatement(node) && ts.isBinaryExpression(node.expression)) {
|
|
121
|
+
const left = node.expression.left;
|
|
122
|
+
if (ts.isPropertyAccessExpression(left)) {
|
|
123
|
+
const text = getPropertyChain(left);
|
|
124
|
+
if (text === 'module.exports') {
|
|
125
|
+
exports.push({
|
|
126
|
+
name: 'default',
|
|
127
|
+
exportedAs: ['default'],
|
|
128
|
+
kind: 'cjs',
|
|
129
|
+
filePath,
|
|
130
|
+
line: lineOf(node, sf),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
else if (text.startsWith('module.exports.')) {
|
|
134
|
+
const name = text.slice('module.exports.'.length);
|
|
135
|
+
exports.push({
|
|
136
|
+
name,
|
|
137
|
+
exportedAs: [name],
|
|
138
|
+
kind: 'cjs',
|
|
139
|
+
filePath,
|
|
140
|
+
line: lineOf(node, sf),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
else if (text.startsWith('exports.')) {
|
|
144
|
+
const name = text.slice('exports.'.length);
|
|
145
|
+
exports.push({
|
|
146
|
+
name,
|
|
147
|
+
exportedAs: [name],
|
|
148
|
+
kind: 'cjs',
|
|
149
|
+
filePath,
|
|
150
|
+
line: lineOf(node, sf),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
ts.forEachChild(node, visit);
|
|
156
|
+
}
|
|
157
|
+
visit(sf);
|
|
158
|
+
return exports;
|
|
159
|
+
}
|
|
160
|
+
function hasExportModifier(node) {
|
|
161
|
+
const mods = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
|
|
162
|
+
return mods?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
163
|
+
}
|
|
164
|
+
function lineOf(node, sf) {
|
|
165
|
+
return sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
166
|
+
}
|
|
167
|
+
function getPropertyChain(node) {
|
|
168
|
+
const parts = [node.name.text];
|
|
169
|
+
let current = node.expression;
|
|
170
|
+
while (ts.isPropertyAccessExpression(current)) {
|
|
171
|
+
parts.unshift(current.name.text);
|
|
172
|
+
current = current.expression;
|
|
173
|
+
}
|
|
174
|
+
if (ts.isIdentifier(current))
|
|
175
|
+
parts.unshift(current.text);
|
|
176
|
+
return parts.join('.');
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=extractExports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractExports.js","sourceRoot":"","sources":["../../../src/analysis/ts/extractExports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import type { RouteIndexEntry } from '../../search/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract route definitions from a TypeScript/JavaScript source file.
|
|
5
|
+
*
|
|
6
|
+
* Supports:
|
|
7
|
+
* - Express/Fastify: app.get('/path', handler), router.post(...)
|
|
8
|
+
* - Next.js App Router: exported GET/POST/etc in route.ts files
|
|
9
|
+
* - Next.js Pages API: default export in pages/api/** files
|
|
10
|
+
* - Route maps: object literals with path/method/handler fields
|
|
11
|
+
*/
|
|
12
|
+
export declare function extractRoutes(sf: ts.SourceFile): RouteIndexEntry[];
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
const HTTP_METHODS = new Set(['get', 'post', 'put', 'patch', 'delete', 'options', 'head', 'all', 'use']);
|
|
4
|
+
const NEXT_HANDLER_NAMES = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD']);
|
|
5
|
+
/**
|
|
6
|
+
* Extract route definitions from a TypeScript/JavaScript source file.
|
|
7
|
+
*
|
|
8
|
+
* Supports:
|
|
9
|
+
* - Express/Fastify: app.get('/path', handler), router.post(...)
|
|
10
|
+
* - Next.js App Router: exported GET/POST/etc in route.ts files
|
|
11
|
+
* - Next.js Pages API: default export in pages/api/** files
|
|
12
|
+
* - Route maps: object literals with path/method/handler fields
|
|
13
|
+
*/
|
|
14
|
+
export function extractRoutes(sf) {
|
|
15
|
+
const entries = [];
|
|
16
|
+
const filePath = sf.fileName;
|
|
17
|
+
const basename = path.basename(filePath, path.extname(filePath));
|
|
18
|
+
const isRouteFile = basename === 'route';
|
|
19
|
+
const isPagesApi = filePath.includes('/pages/api/') || filePath.includes('/pages\\api\\');
|
|
20
|
+
function visit(node) {
|
|
21
|
+
// A. Express/Fastify-style: app.get('/path', handler)
|
|
22
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
|
|
23
|
+
const method = node.expression.name.text.toLowerCase();
|
|
24
|
+
if (HTTP_METHODS.has(method) && node.arguments.length >= 1) {
|
|
25
|
+
const firstArg = node.arguments[0];
|
|
26
|
+
if (ts.isStringLiteral(firstArg) || ts.isNoSubstitutionTemplateLiteral(firstArg)) {
|
|
27
|
+
const routePath = firstArg.text;
|
|
28
|
+
const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
29
|
+
const callee = getCalleeText(node.expression.expression);
|
|
30
|
+
entries.push({
|
|
31
|
+
filePath, line,
|
|
32
|
+
method: method === 'use' ? undefined : method.toUpperCase(),
|
|
33
|
+
path: routePath,
|
|
34
|
+
framework: callee?.includes('fastify') ? 'fastify' : 'express',
|
|
35
|
+
enclosingSymbol: callee,
|
|
36
|
+
tokens: tokenize(`${method} ${routePath} ${callee ?? ''}`),
|
|
37
|
+
text: `${method.toUpperCase()} ${routePath}`,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// B. Fastify route({ method, url, handler })
|
|
43
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
|
|
44
|
+
if (node.expression.name.text === 'route' && node.arguments.length >= 1) {
|
|
45
|
+
const arg = node.arguments[0];
|
|
46
|
+
if (ts.isObjectLiteralExpression(arg)) {
|
|
47
|
+
const method = getPropertyValue(arg, 'method');
|
|
48
|
+
const url = getPropertyValue(arg, 'url');
|
|
49
|
+
if (method && url) {
|
|
50
|
+
const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
51
|
+
entries.push({
|
|
52
|
+
filePath, line,
|
|
53
|
+
method: method.toUpperCase(),
|
|
54
|
+
path: url,
|
|
55
|
+
framework: 'fastify',
|
|
56
|
+
tokens: tokenize(`${method} ${url} route`),
|
|
57
|
+
text: `${method.toUpperCase()} ${url}`,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// C. Next.js App Router: exported GET, POST, etc. in route.ts
|
|
64
|
+
if (isRouteFile && isExportedNamedDeclaration(node)) {
|
|
65
|
+
const name = getExportedName(node);
|
|
66
|
+
if (name && NEXT_HANDLER_NAMES.has(name)) {
|
|
67
|
+
const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
68
|
+
const routePath = deriveRouteFromFilePath(filePath);
|
|
69
|
+
entries.push({
|
|
70
|
+
filePath, line,
|
|
71
|
+
method: name,
|
|
72
|
+
path: routePath,
|
|
73
|
+
framework: 'next-app-router',
|
|
74
|
+
enclosingSymbol: name,
|
|
75
|
+
tokens: tokenize(`${name} ${routePath ?? ''} next handler`),
|
|
76
|
+
text: `${name} ${routePath ?? filePath}`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// D. Next.js Pages API: default export in pages/api/**
|
|
81
|
+
if (isPagesApi && ts.isExportAssignment(node)) {
|
|
82
|
+
const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
83
|
+
const routePath = deriveRouteFromFilePath(filePath);
|
|
84
|
+
entries.push({
|
|
85
|
+
filePath, line,
|
|
86
|
+
path: routePath,
|
|
87
|
+
framework: 'next-pages-api',
|
|
88
|
+
tokens: tokenize(`${routePath ?? ''} api handler pages`),
|
|
89
|
+
text: `handler ${routePath ?? filePath}`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// E. Route map: object with path/route/method/handler keys
|
|
93
|
+
if (ts.isObjectLiteralExpression(node) && node.properties.length >= 2) {
|
|
94
|
+
const hasPath = hasProperty(node, 'path') || hasProperty(node, 'route');
|
|
95
|
+
const hasHandler = hasProperty(node, 'handler') || hasProperty(node, 'component') || hasProperty(node, 'action');
|
|
96
|
+
if (hasPath && hasHandler) {
|
|
97
|
+
const routePath = getPropertyValue(node, 'path') ?? getPropertyValue(node, 'route');
|
|
98
|
+
const method = getPropertyValue(node, 'method');
|
|
99
|
+
const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
100
|
+
entries.push({
|
|
101
|
+
filePath, line,
|
|
102
|
+
method: method?.toUpperCase(),
|
|
103
|
+
path: routePath,
|
|
104
|
+
framework: 'route-map',
|
|
105
|
+
tokens: tokenize(`${method ?? ''} ${routePath ?? ''} route map`),
|
|
106
|
+
text: `${method?.toUpperCase() ?? 'ROUTE'} ${routePath ?? '?'}`,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
ts.forEachChild(node, visit);
|
|
111
|
+
}
|
|
112
|
+
visit(sf);
|
|
113
|
+
return entries;
|
|
114
|
+
}
|
|
115
|
+
function getCalleeText(expr) {
|
|
116
|
+
if (ts.isIdentifier(expr))
|
|
117
|
+
return expr.text;
|
|
118
|
+
if (ts.isPropertyAccessExpression(expr))
|
|
119
|
+
return getCalleeText(expr.expression);
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
function isExportedNamedDeclaration(node) {
|
|
123
|
+
if (ts.isFunctionDeclaration(node) || ts.isVariableStatement(node)) {
|
|
124
|
+
const mods = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
|
|
125
|
+
return mods?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
126
|
+
}
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
function getExportedName(node) {
|
|
130
|
+
if (ts.isFunctionDeclaration(node) && node.name)
|
|
131
|
+
return node.name.text;
|
|
132
|
+
if (ts.isVariableStatement(node)) {
|
|
133
|
+
for (const decl of node.declarationList.declarations) {
|
|
134
|
+
if (ts.isIdentifier(decl.name))
|
|
135
|
+
return decl.name.text;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
function hasProperty(obj, name) {
|
|
141
|
+
return obj.properties.some((p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === name);
|
|
142
|
+
}
|
|
143
|
+
function getPropertyValue(obj, name) {
|
|
144
|
+
for (const p of obj.properties) {
|
|
145
|
+
if (ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === name) {
|
|
146
|
+
if (ts.isStringLiteral(p.initializer))
|
|
147
|
+
return p.initializer.text;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
function deriveRouteFromFilePath(filePath) {
|
|
153
|
+
// Next.js: derive /api/foo from pages/api/foo.ts or app/api/foo/route.ts
|
|
154
|
+
const pagesMatch = filePath.match(/pages[/\\]api[/\\](.+?)(?:\/index)?\.\w+$/);
|
|
155
|
+
if (pagesMatch)
|
|
156
|
+
return `/api/${pagesMatch[1].replace(/\\/g, '/')}`;
|
|
157
|
+
const appMatch = filePath.match(/app[/\\](.+?)[/\\]route\.\w+$/);
|
|
158
|
+
if (appMatch)
|
|
159
|
+
return `/${appMatch[1].replace(/\\/g, '/')}`;
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
function tokenize(text) {
|
|
163
|
+
return text.toLowerCase().replace(/[^a-z0-9/\s-_]/g, ' ').split(/[\s-_/]+/).filter((t) => t.length > 1);
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=extractRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractRoutes.js","sourceRoot":"","sources":["../../../src/analysis/ts/extractRoutes.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,9 +2,13 @@ import ts from 'typescript';
|
|
|
2
2
|
/**
|
|
3
3
|
* Parse a TypeScript/JavaScript file into a ts.SourceFile using the TypeScript compiler API.
|
|
4
4
|
* Supports: .ts, .tsx, .js, .jsx, .mjs, .cjs
|
|
5
|
+
*
|
|
6
|
+
* @param text - Optional overlay text. If provided, skips disk read and parses this content
|
|
7
|
+
* instead. Used by Phase 2A snapshot-aware indexing for unsaved-buffer support.
|
|
8
|
+
*
|
|
5
9
|
* Returns null if the file doesn't exist or can't be parsed.
|
|
6
10
|
*/
|
|
7
|
-
export declare function parseSourceFile(filePath: string): ts.SourceFile | null;
|
|
11
|
+
export declare function parseSourceFile(filePath: string, text?: string): ts.SourceFile | null;
|
|
8
12
|
/**
|
|
9
13
|
* Parse source content directly (for base-version comparison).
|
|
10
14
|
*/
|
|
@@ -4,11 +4,15 @@ import { scriptKindForFile } from '../../search/fileKinds.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* Parse a TypeScript/JavaScript file into a ts.SourceFile using the TypeScript compiler API.
|
|
6
6
|
* Supports: .ts, .tsx, .js, .jsx, .mjs, .cjs
|
|
7
|
+
*
|
|
8
|
+
* @param text - Optional overlay text. If provided, skips disk read and parses this content
|
|
9
|
+
* instead. Used by Phase 2A snapshot-aware indexing for unsaved-buffer support.
|
|
10
|
+
*
|
|
7
11
|
* Returns null if the file doesn't exist or can't be parsed.
|
|
8
12
|
*/
|
|
9
|
-
export function parseSourceFile(filePath) {
|
|
13
|
+
export function parseSourceFile(filePath, text) {
|
|
10
14
|
try {
|
|
11
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
15
|
+
const content = text ?? fs.readFileSync(filePath, 'utf-8');
|
|
12
16
|
return ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, scriptKindForFile(filePath));
|
|
13
17
|
}
|
|
14
18
|
catch {
|
|
@@ -1 +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;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D
|
|
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;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,IAAa;IAC7D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3D,OAAO,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3G,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,QAAgB;IAClE,OAAO,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC3G,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Focused TypeScript semantic query helpers built on a ts.Program.
|
|
4
|
+
*
|
|
5
|
+
* These answer questions that AST analysis alone cannot answer reliably.
|
|
6
|
+
* All methods are read-only and do not modify the program state.
|
|
7
|
+
*
|
|
8
|
+
* Keep integration points narrow: callers should ask for specific facts,
|
|
9
|
+
* not raw ts.Type objects.
|
|
10
|
+
*/
|
|
11
|
+
export declare class CheckerQueries {
|
|
12
|
+
private readonly program;
|
|
13
|
+
private checker;
|
|
14
|
+
constructor(program: ts.Program);
|
|
15
|
+
/**
|
|
16
|
+
* Get the string-valued members of an exported enum.
|
|
17
|
+
* Returns null if the enum cannot be found in the program.
|
|
18
|
+
*/
|
|
19
|
+
getEnumMembers(filePath: string, enumName: string): string[] | null;
|
|
20
|
+
/**
|
|
21
|
+
* Given a switch statement (by containing function / file and line),
|
|
22
|
+
* return which enum members are handled and which are missing.
|
|
23
|
+
*/
|
|
24
|
+
getSwitchExhaustiveness(filePath: string, enumFilePath: string, enumName: string): {
|
|
25
|
+
handled: string[];
|
|
26
|
+
missing: string[];
|
|
27
|
+
isExhaustive: boolean;
|
|
28
|
+
} | null;
|
|
29
|
+
/**
|
|
30
|
+
* Get the type text of an exported symbol in a file.
|
|
31
|
+
* Returns a human-readable type string, or null if not found.
|
|
32
|
+
*/
|
|
33
|
+
getExportedSymbolType(filePath: string, symbolName: string): string | null;
|
|
34
|
+
/**
|
|
35
|
+
* Get parameter facts for an exported function: name, type text, optional status.
|
|
36
|
+
*/
|
|
37
|
+
getFunctionParams(filePath: string, funcName: string): Array<{
|
|
38
|
+
name: string;
|
|
39
|
+
typeText: string;
|
|
40
|
+
optional: boolean;
|
|
41
|
+
rest: boolean;
|
|
42
|
+
}> | null;
|
|
43
|
+
/**
|
|
44
|
+
* Get the return type text for an exported function.
|
|
45
|
+
*/
|
|
46
|
+
getReturnType(filePath: string, funcName: string): string | null;
|
|
47
|
+
/**
|
|
48
|
+
* Get semantic diagnostics for a file.
|
|
49
|
+
* Lighter than running the full LSP — useful for quick checks.
|
|
50
|
+
*/
|
|
51
|
+
getSemanticDiagnostics(filePath: string): readonly ts.Diagnostic[];
|
|
52
|
+
/**
|
|
53
|
+
* Get all files in the program (resolved root names).
|
|
54
|
+
*/
|
|
55
|
+
getProgramFiles(): string[];
|
|
56
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Focused TypeScript semantic query helpers built on a ts.Program.
|
|
4
|
+
*
|
|
5
|
+
* These answer questions that AST analysis alone cannot answer reliably.
|
|
6
|
+
* All methods are read-only and do not modify the program state.
|
|
7
|
+
*
|
|
8
|
+
* Keep integration points narrow: callers should ask for specific facts,
|
|
9
|
+
* not raw ts.Type objects.
|
|
10
|
+
*/
|
|
11
|
+
export class CheckerQueries {
|
|
12
|
+
program;
|
|
13
|
+
checker;
|
|
14
|
+
constructor(program) {
|
|
15
|
+
this.program = program;
|
|
16
|
+
this.checker = program.getTypeChecker();
|
|
17
|
+
}
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Enum queries
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
/**
|
|
22
|
+
* Get the string-valued members of an exported enum.
|
|
23
|
+
* Returns null if the enum cannot be found in the program.
|
|
24
|
+
*/
|
|
25
|
+
getEnumMembers(filePath, enumName) {
|
|
26
|
+
const sf = this.program.getSourceFile(filePath);
|
|
27
|
+
if (!sf)
|
|
28
|
+
return null;
|
|
29
|
+
let enumDecl;
|
|
30
|
+
ts.forEachChild(sf, (node) => {
|
|
31
|
+
if (ts.isEnumDeclaration(node) && node.name.text === enumName) {
|
|
32
|
+
enumDecl = node;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
if (!enumDecl)
|
|
36
|
+
return null;
|
|
37
|
+
return enumDecl.members.map((m) => ts.isIdentifier(m.name) ? m.name.text : m.name.getText(sf));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Given a switch statement (by containing function / file and line),
|
|
41
|
+
* return which enum members are handled and which are missing.
|
|
42
|
+
*/
|
|
43
|
+
getSwitchExhaustiveness(filePath, enumFilePath, enumName) {
|
|
44
|
+
const allMembers = this.getEnumMembers(enumFilePath, enumName);
|
|
45
|
+
if (!allMembers)
|
|
46
|
+
return null;
|
|
47
|
+
const sf = this.program.getSourceFile(filePath);
|
|
48
|
+
if (!sf)
|
|
49
|
+
return null;
|
|
50
|
+
const handled = new Set();
|
|
51
|
+
const visit = (node) => {
|
|
52
|
+
if (ts.isSwitchStatement(node)) {
|
|
53
|
+
for (const clause of node.caseBlock.clauses) {
|
|
54
|
+
if (ts.isCaseClause(clause)) {
|
|
55
|
+
// Check if the case expression is an enum member access
|
|
56
|
+
if (ts.isPropertyAccessExpression(clause.expression)) {
|
|
57
|
+
const memberName = clause.expression.name.text;
|
|
58
|
+
if (allMembers.includes(memberName)) {
|
|
59
|
+
handled.add(memberName);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
ts.forEachChild(node, visit);
|
|
66
|
+
};
|
|
67
|
+
visit(sf);
|
|
68
|
+
const missing = allMembers.filter((m) => !handled.has(m));
|
|
69
|
+
return { handled: [...handled], missing, isExhaustive: missing.length === 0 };
|
|
70
|
+
}
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Function / type queries
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
/**
|
|
75
|
+
* Get the type text of an exported symbol in a file.
|
|
76
|
+
* Returns a human-readable type string, or null if not found.
|
|
77
|
+
*/
|
|
78
|
+
getExportedSymbolType(filePath, symbolName) {
|
|
79
|
+
const sf = this.program.getSourceFile(filePath);
|
|
80
|
+
if (!sf)
|
|
81
|
+
return null;
|
|
82
|
+
let result = null;
|
|
83
|
+
const visit = (node) => {
|
|
84
|
+
if (result)
|
|
85
|
+
return;
|
|
86
|
+
// Function declarations
|
|
87
|
+
if (ts.isFunctionDeclaration(node) && node.name?.text === symbolName) {
|
|
88
|
+
const sym = this.checker.getSymbolAtLocation(node.name);
|
|
89
|
+
if (sym)
|
|
90
|
+
result = this.checker.typeToString(this.checker.getTypeOfSymbolAtLocation(sym, node));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// Variable declarations
|
|
94
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === symbolName) {
|
|
95
|
+
const sym = this.checker.getSymbolAtLocation(node.name);
|
|
96
|
+
if (sym)
|
|
97
|
+
result = this.checker.typeToString(this.checker.getTypeOfSymbolAtLocation(sym, node));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
ts.forEachChild(node, visit);
|
|
101
|
+
};
|
|
102
|
+
visit(sf);
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get parameter facts for an exported function: name, type text, optional status.
|
|
107
|
+
*/
|
|
108
|
+
getFunctionParams(filePath, funcName) {
|
|
109
|
+
const sf = this.program.getSourceFile(filePath);
|
|
110
|
+
if (!sf)
|
|
111
|
+
return null;
|
|
112
|
+
let funcNode;
|
|
113
|
+
const visit = (node) => {
|
|
114
|
+
if (funcNode)
|
|
115
|
+
return;
|
|
116
|
+
if (ts.isFunctionDeclaration(node) && node.name?.text === funcName) {
|
|
117
|
+
funcNode = node;
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === funcName) {
|
|
121
|
+
if (node.initializer && (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))) {
|
|
122
|
+
funcNode = node.initializer;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
ts.forEachChild(node, visit);
|
|
127
|
+
};
|
|
128
|
+
visit(sf);
|
|
129
|
+
if (!funcNode)
|
|
130
|
+
return null;
|
|
131
|
+
return funcNode.parameters.map((p) => ({
|
|
132
|
+
name: ts.isIdentifier(p.name) ? p.name.text : p.name.getText(sf),
|
|
133
|
+
typeText: p.type ? p.type.getText(sf) : this.checker.typeToString(this.checker.getTypeAtLocation(p)),
|
|
134
|
+
optional: !!p.questionToken || !!p.initializer,
|
|
135
|
+
rest: !!p.dotDotDotToken,
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get the return type text for an exported function.
|
|
140
|
+
*/
|
|
141
|
+
getReturnType(filePath, funcName) {
|
|
142
|
+
const sf = this.program.getSourceFile(filePath);
|
|
143
|
+
if (!sf)
|
|
144
|
+
return null;
|
|
145
|
+
let result = null;
|
|
146
|
+
const visit = (node) => {
|
|
147
|
+
if (result)
|
|
148
|
+
return;
|
|
149
|
+
if (ts.isFunctionDeclaration(node) && node.name?.text === funcName) {
|
|
150
|
+
const sig = this.checker.getSignatureFromDeclaration(node);
|
|
151
|
+
if (sig)
|
|
152
|
+
result = this.checker.typeToString(sig.getReturnType());
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
ts.forEachChild(node, visit);
|
|
156
|
+
};
|
|
157
|
+
visit(sf);
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
// Diagnostics
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
/**
|
|
164
|
+
* Get semantic diagnostics for a file.
|
|
165
|
+
* Lighter than running the full LSP — useful for quick checks.
|
|
166
|
+
*/
|
|
167
|
+
getSemanticDiagnostics(filePath) {
|
|
168
|
+
const sf = this.program.getSourceFile(filePath);
|
|
169
|
+
if (!sf)
|
|
170
|
+
return [];
|
|
171
|
+
try {
|
|
172
|
+
return this.program.getSemanticDiagnostics(sf);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get all files in the program (resolved root names).
|
|
180
|
+
*/
|
|
181
|
+
getProgramFiles() {
|
|
182
|
+
return this.program.getSourceFiles()
|
|
183
|
+
.map((sf) => sf.fileName)
|
|
184
|
+
.filter((f) => !f.includes('node_modules') && !f.endsWith('.d.ts'));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=CheckerQueries.js.map
|