prinfer 0.5.3 → 0.6.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 +23 -12
- package/dist/cli.cjs +253 -94
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +253 -94
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +298 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -1
- package/dist/index.d.ts +66 -1
- package/dist/index.js +294 -12
- package/dist/index.js.map +1 -1
- package/dist/mcp.cjs +232 -76
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +232 -76
- package/dist/mcp.js.map +1 -1
- package/package.json +1 -1
package/dist/mcp.js
CHANGED
|
@@ -48,66 +48,203 @@ function loadProgram(entryFileAbs, project) {
|
|
|
48
48
|
function isArrowOrFnExpr(n) {
|
|
49
49
|
return !!n && (ts.isArrowFunction(n) || ts.isFunctionExpression(n));
|
|
50
50
|
}
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if ((ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) && nodeNameText(node.name) === name) {
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
if (ts.isPropertyAssignment(node) && nodeNameText(node.name) === name) {
|
|
67
|
-
return isArrowOrFnExpr(node.initializer);
|
|
51
|
+
function findSmallestNodeAtPosition(sourceFile, position) {
|
|
52
|
+
let result;
|
|
53
|
+
function visit(node) {
|
|
54
|
+
const start = node.getStart(sourceFile);
|
|
55
|
+
const end = node.getEnd();
|
|
56
|
+
if (position < start || position >= end) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!result || node.getWidth(sourceFile) <= result.getWidth(sourceFile)) {
|
|
60
|
+
result = node;
|
|
61
|
+
}
|
|
62
|
+
ts.forEachChild(node, visit);
|
|
68
63
|
}
|
|
69
|
-
|
|
64
|
+
visit(sourceFile);
|
|
65
|
+
return result;
|
|
70
66
|
}
|
|
71
|
-
function
|
|
72
|
-
|
|
67
|
+
function findHoverableAncestor(sourceFile, position) {
|
|
68
|
+
const smallestNode = findSmallestNodeAtPosition(sourceFile, position);
|
|
69
|
+
if (!smallestNode) return void 0;
|
|
70
|
+
let bestMatch = smallestNode;
|
|
71
|
+
function visit(n) {
|
|
72
|
+
const start = n.getStart(sourceFile);
|
|
73
|
+
const end = n.getEnd();
|
|
74
|
+
if (position < start || position >= end) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (ts.isCallExpression(n)) {
|
|
78
|
+
const expr = n.expression;
|
|
79
|
+
if (ts.isIdentifier(expr)) {
|
|
80
|
+
if (position >= expr.getStart(sourceFile) && position < expr.getEnd()) {
|
|
81
|
+
bestMatch = n;
|
|
82
|
+
}
|
|
83
|
+
} else if (ts.isPropertyAccessExpression(expr)) {
|
|
84
|
+
if (position >= expr.name.getStart(sourceFile) && position < expr.name.getEnd()) {
|
|
85
|
+
bestMatch = n;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (ts.isFunctionDeclaration(n) && n.name) {
|
|
90
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
91
|
+
bestMatch = n;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (ts.isVariableDeclaration(n) && ts.isIdentifier(n.name)) {
|
|
95
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
96
|
+
bestMatch = n;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if ((ts.isMethodDeclaration(n) || ts.isMethodSignature(n)) && ts.isIdentifier(n.name)) {
|
|
100
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
101
|
+
bestMatch = n;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (ts.isClassDeclaration(n) && n.name) {
|
|
105
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
106
|
+
bestMatch = n;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (ts.isInterfaceDeclaration(n) && n.name) {
|
|
110
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
111
|
+
bestMatch = n;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
ts.forEachChild(n, visit);
|
|
73
115
|
return true;
|
|
74
116
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
function isNamedNode(node, name) {
|
|
78
|
-
return isFunctionLikeNamed(node, name) || isVariableNamed(node, name);
|
|
117
|
+
visit(sourceFile);
|
|
118
|
+
return bestMatch;
|
|
79
119
|
}
|
|
80
|
-
function
|
|
81
|
-
const
|
|
82
|
-
|
|
120
|
+
function findNodeAtPosition(sourceFile, line, column) {
|
|
121
|
+
const lineCount = sourceFile.getLineStarts().length;
|
|
122
|
+
if (line < 1 || line > lineCount) {
|
|
123
|
+
return void 0;
|
|
124
|
+
}
|
|
125
|
+
const lineStart = sourceFile.getLineStarts()[line - 1];
|
|
126
|
+
const lineEnd = line < lineCount ? sourceFile.getLineStarts()[line] : sourceFile.getEnd();
|
|
127
|
+
const lineLength = lineEnd - lineStart;
|
|
128
|
+
if (column < 1 || column > lineLength + 1) {
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
131
|
+
const position = sourceFile.getPositionOfLineAndCharacter(
|
|
132
|
+
line - 1,
|
|
133
|
+
column - 1
|
|
83
134
|
);
|
|
84
|
-
return
|
|
135
|
+
return findHoverableAncestor(sourceFile, position);
|
|
85
136
|
}
|
|
86
|
-
function
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
} else {
|
|
98
|
-
found = node;
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
137
|
+
function getSymbolKind(node) {
|
|
138
|
+
if (ts.isFunctionDeclaration(node)) return "function";
|
|
139
|
+
if (ts.isArrowFunction(node)) return "function";
|
|
140
|
+
if (ts.isFunctionExpression(node)) return "function";
|
|
141
|
+
if (ts.isMethodDeclaration(node)) return "method";
|
|
142
|
+
if (ts.isMethodSignature(node)) return "method";
|
|
143
|
+
if (ts.isVariableDeclaration(node)) {
|
|
144
|
+
const init = node.initializer;
|
|
145
|
+
if (init && (ts.isArrowFunction(init) || ts.isFunctionExpression(init))) {
|
|
146
|
+
return "function";
|
|
101
147
|
}
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return
|
|
148
|
+
return "variable";
|
|
149
|
+
}
|
|
150
|
+
if (ts.isParameter(node)) return "parameter";
|
|
151
|
+
if (ts.isPropertyDeclaration(node)) return "property";
|
|
152
|
+
if (ts.isPropertySignature(node)) return "property";
|
|
153
|
+
if (ts.isPropertyAccessExpression(node)) return "property";
|
|
154
|
+
if (ts.isCallExpression(node)) return "call";
|
|
155
|
+
if (ts.isTypeAliasDeclaration(node)) return "type";
|
|
156
|
+
if (ts.isInterfaceDeclaration(node)) return "interface";
|
|
157
|
+
if (ts.isClassDeclaration(node)) return "class";
|
|
158
|
+
if (ts.isIdentifier(node)) return "identifier";
|
|
159
|
+
return "unknown";
|
|
160
|
+
}
|
|
161
|
+
function getNodeName(node) {
|
|
162
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
163
|
+
return node.name.text;
|
|
164
|
+
}
|
|
165
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
166
|
+
return node.name.text;
|
|
167
|
+
}
|
|
168
|
+
if ((ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) && ts.isIdentifier(node.name)) {
|
|
169
|
+
return node.name.text;
|
|
170
|
+
}
|
|
171
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
172
|
+
return node.name.text;
|
|
173
|
+
}
|
|
174
|
+
if (ts.isCallExpression(node)) {
|
|
175
|
+
const expr = node.expression;
|
|
176
|
+
if (ts.isIdentifier(expr)) return expr.text;
|
|
177
|
+
if (ts.isPropertyAccessExpression(expr)) return expr.name.text;
|
|
178
|
+
}
|
|
179
|
+
if (ts.isParameter(node) && ts.isIdentifier(node.name)) {
|
|
180
|
+
return node.name.text;
|
|
181
|
+
}
|
|
182
|
+
if (ts.isIdentifier(node)) {
|
|
183
|
+
return node.text;
|
|
184
|
+
}
|
|
185
|
+
if (ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isClassDeclaration(node)) {
|
|
186
|
+
return node.name?.text;
|
|
187
|
+
}
|
|
188
|
+
return void 0;
|
|
189
|
+
}
|
|
190
|
+
function getDocumentation(checker, symbol) {
|
|
191
|
+
if (!symbol) return void 0;
|
|
192
|
+
const docs = symbol.getDocumentationComment(checker);
|
|
193
|
+
if (docs.length === 0) return void 0;
|
|
194
|
+
return ts.displayPartsToString(docs);
|
|
106
195
|
}
|
|
107
|
-
function
|
|
196
|
+
function getHoverInfo(program, node, sourceFile, includeDocs) {
|
|
108
197
|
const checker = program.getTypeChecker();
|
|
109
|
-
const sf = sourceFile
|
|
110
|
-
const line =
|
|
198
|
+
const sf = sourceFile;
|
|
199
|
+
const { line, character } = sf.getLineAndCharacterOfPosition(
|
|
200
|
+
node.getStart(sf)
|
|
201
|
+
);
|
|
202
|
+
const flags = ts.TypeFormatFlags.NoTruncation;
|
|
203
|
+
const kind = getSymbolKind(node);
|
|
204
|
+
const name = getNodeName(node);
|
|
205
|
+
let symbol;
|
|
206
|
+
if (ts.isCallExpression(node)) {
|
|
207
|
+
const expr = node.expression;
|
|
208
|
+
if (ts.isPropertyAccessExpression(expr)) {
|
|
209
|
+
symbol = checker.getSymbolAtLocation(expr.name);
|
|
210
|
+
} else {
|
|
211
|
+
symbol = checker.getSymbolAtLocation(expr);
|
|
212
|
+
}
|
|
213
|
+
} else {
|
|
214
|
+
const nodeWithName2 = node;
|
|
215
|
+
if (nodeWithName2.name) {
|
|
216
|
+
symbol = checker.getSymbolAtLocation(nodeWithName2.name);
|
|
217
|
+
} else {
|
|
218
|
+
symbol = checker.getSymbolAtLocation(node);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const documentation = includeDocs ? getDocumentation(checker, symbol) : void 0;
|
|
222
|
+
if (ts.isCallExpression(node)) {
|
|
223
|
+
const sig2 = checker.getResolvedSignature(node);
|
|
224
|
+
if (sig2) {
|
|
225
|
+
const signature = checker.signatureToString(sig2, void 0, flags);
|
|
226
|
+
const ret = checker.getReturnTypeOfSignature(sig2);
|
|
227
|
+
const returnType = checker.typeToString(ret, void 0, flags);
|
|
228
|
+
return {
|
|
229
|
+
signature,
|
|
230
|
+
returnType,
|
|
231
|
+
line: line + 1,
|
|
232
|
+
column: character + 1,
|
|
233
|
+
documentation,
|
|
234
|
+
kind,
|
|
235
|
+
name
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const t2 = checker.getTypeAtLocation(node);
|
|
239
|
+
return {
|
|
240
|
+
signature: checker.typeToString(t2, void 0, flags),
|
|
241
|
+
line: line + 1,
|
|
242
|
+
column: character + 1,
|
|
243
|
+
documentation,
|
|
244
|
+
kind,
|
|
245
|
+
name
|
|
246
|
+
};
|
|
247
|
+
}
|
|
111
248
|
let sig;
|
|
112
249
|
if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
|
|
113
250
|
sig = checker.getSignatureFromDeclaration(node) ?? void 0;
|
|
@@ -122,26 +259,39 @@ function getTypeInfo(program, node, sourceFile) {
|
|
|
122
259
|
} else if (ts.isMethodSignature(node)) {
|
|
123
260
|
sig = checker.getSignatureFromDeclaration(node) ?? void 0;
|
|
124
261
|
}
|
|
125
|
-
const flags = ts.TypeFormatFlags.NoTruncation;
|
|
126
262
|
if (sig) {
|
|
127
263
|
const signature = checker.signatureToString(sig, void 0, flags);
|
|
128
264
|
const ret = checker.getReturnTypeOfSignature(sig);
|
|
129
265
|
const returnType = checker.typeToString(ret, void 0, flags);
|
|
130
|
-
return {
|
|
266
|
+
return {
|
|
267
|
+
signature,
|
|
268
|
+
returnType,
|
|
269
|
+
line: line + 1,
|
|
270
|
+
column: character + 1,
|
|
271
|
+
documentation,
|
|
272
|
+
kind,
|
|
273
|
+
name
|
|
274
|
+
};
|
|
131
275
|
}
|
|
132
276
|
const nodeWithName = node;
|
|
133
|
-
let
|
|
277
|
+
let targetNode = node;
|
|
134
278
|
if (nodeWithName.name && ts.isIdentifier(nodeWithName.name)) {
|
|
135
|
-
|
|
279
|
+
targetNode = nodeWithName.name;
|
|
136
280
|
}
|
|
137
|
-
const t = checker.getTypeAtLocation(
|
|
138
|
-
return {
|
|
281
|
+
const t = checker.getTypeAtLocation(targetNode);
|
|
282
|
+
return {
|
|
283
|
+
signature: checker.typeToString(t, void 0, flags),
|
|
284
|
+
line: line + 1,
|
|
285
|
+
column: character + 1,
|
|
286
|
+
documentation,
|
|
287
|
+
kind,
|
|
288
|
+
name
|
|
289
|
+
};
|
|
139
290
|
}
|
|
140
291
|
|
|
141
292
|
// src/index.ts
|
|
142
|
-
function
|
|
143
|
-
const
|
|
144
|
-
const { line, project } = opts;
|
|
293
|
+
function hover(file, line, column, options) {
|
|
294
|
+
const { project, include_docs = false } = options ?? {};
|
|
145
295
|
const entryFileAbs = path2.resolve(process.cwd(), file);
|
|
146
296
|
if (!fs.existsSync(entryFileAbs)) {
|
|
147
297
|
throw new Error(`File not found: ${entryFileAbs}`);
|
|
@@ -153,14 +303,11 @@ function inferType(file, name, options) {
|
|
|
153
303
|
`Could not load source file into the program (check tsconfig include/exclude): ${entryFileAbs}`
|
|
154
304
|
);
|
|
155
305
|
}
|
|
156
|
-
const node =
|
|
306
|
+
const node = findNodeAtPosition(sourceFile, line, column);
|
|
157
307
|
if (!node) {
|
|
158
|
-
|
|
159
|
-
throw new Error(
|
|
160
|
-
`No symbol named "${name}"${lineInfo} found in ${entryFileAbs}`
|
|
161
|
-
);
|
|
308
|
+
throw new Error(`No symbol found at ${entryFileAbs}:${line}:${column}`);
|
|
162
309
|
}
|
|
163
|
-
return
|
|
310
|
+
return getHoverInfo(program, node, sourceFile, include_docs);
|
|
164
311
|
}
|
|
165
312
|
|
|
166
313
|
// src/mcp.ts
|
|
@@ -177,8 +324,8 @@ Manual setup:
|
|
|
177
324
|
Run: claude mcp add prinfer node /path/to/prinfer-mcp
|
|
178
325
|
|
|
179
326
|
Provided tools:
|
|
180
|
-
|
|
181
|
-
|
|
327
|
+
hover(file, line, column, include_docs?, project?)
|
|
328
|
+
Get TypeScript type information at a specific position.
|
|
182
329
|
|
|
183
330
|
See also:
|
|
184
331
|
prinfer --help CLI for direct type inspection
|
|
@@ -189,28 +336,37 @@ if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
|
189
336
|
}
|
|
190
337
|
var server = new McpServer({
|
|
191
338
|
name: "prinfer",
|
|
192
|
-
version: "0.
|
|
339
|
+
version: "0.3.0"
|
|
193
340
|
});
|
|
194
341
|
server.tool(
|
|
195
|
-
"
|
|
196
|
-
"
|
|
342
|
+
"hover",
|
|
343
|
+
"Get TypeScript type information at a specific position in a file. Returns the type signature, return type, documentation, and symbol kind.",
|
|
197
344
|
{
|
|
198
345
|
file: z.string().describe("Path to the TypeScript file"),
|
|
199
|
-
|
|
200
|
-
|
|
346
|
+
line: z.number().describe("1-based line number"),
|
|
347
|
+
column: z.number().describe("1-based column (character position)"),
|
|
348
|
+
include_docs: z.boolean().optional().describe("Include JSDoc/TSDoc documentation"),
|
|
201
349
|
project: z.string().optional().describe("Optional path to tsconfig.json")
|
|
202
350
|
},
|
|
203
|
-
async ({ file,
|
|
351
|
+
async ({ file, line, column, include_docs, project }) => {
|
|
204
352
|
try {
|
|
205
|
-
const result =
|
|
353
|
+
const result = hover(file, line, column, { include_docs, project });
|
|
206
354
|
let text = `Type: ${result.signature}`;
|
|
207
355
|
if (result.returnType) {
|
|
208
356
|
text += `
|
|
209
357
|
Returns: ${result.returnType}`;
|
|
210
358
|
}
|
|
211
|
-
if (result.
|
|
359
|
+
if (result.name) {
|
|
360
|
+
text += `
|
|
361
|
+
Name: ${result.name}`;
|
|
362
|
+
}
|
|
363
|
+
text += `
|
|
364
|
+
Kind: ${result.kind}`;
|
|
365
|
+
text += `
|
|
366
|
+
Position: ${result.line}:${result.column}`;
|
|
367
|
+
if (result.documentation) {
|
|
212
368
|
text += `
|
|
213
|
-
|
|
369
|
+
Documentation: ${result.documentation}`;
|
|
214
370
|
}
|
|
215
371
|
return { content: [{ type: "text", text }] };
|
|
216
372
|
} catch (error) {
|
package/dist/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp.ts","../src/index.ts","../src/core.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { inferType } from \"./index.js\";\n\nconst HELP = `\nprinfer-mcp - MCP server for TypeScript type inference\n\nThis is an MCP (Model Context Protocol) server. It's designed to be run\nby Claude Code, not directly from the command line.\n\nSetup:\n Run 'prinfer setup' to configure Claude Code automatically.\n\nManual setup:\n Run: claude mcp add prinfer node /path/to/prinfer-mcp\n\nProvided tools:\n infer_type(file, name, line?, project?)\n Infer the TypeScript type of a function or variable.\n\nSee also:\n prinfer --help CLI for direct type inspection\n`.trim();\n\nif (process.argv.includes(\"--help\") || process.argv.includes(\"-h\")) {\n\tconsole.log(HELP);\n\tprocess.exit(0);\n}\n\nconst server = new McpServer({\n\tname: \"prinfer\",\n\tversion: \"0.2.1\",\n});\n\nserver.tool(\n\t\"infer_type\",\n\t\"Infer the TypeScript type of a function or variable in a file. Returns the type signature and optionally the return type for functions.\",\n\t{\n\t\tfile: z.string().describe(\"Path to the TypeScript file\"),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.describe(\"Name of the function or variable to inspect\"),\n\t\tline: z\n\t\t\t.number()\n\t\t\t.optional()\n\t\t\t.describe(\"Optional line number to narrow search (1-based)\"),\n\t\tproject: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe(\"Optional path to tsconfig.json\"),\n\t},\n\tasync ({ file, name, line, project }) => {\n\t\ttry {\n\t\t\tconst result = inferType(file, name, { line, project });\n\t\t\tlet text = `Type: ${result.signature}`;\n\t\t\tif (result.returnType) {\n\t\t\t\ttext += `\\nReturns: ${result.returnType}`;\n\t\t\t}\n\t\t\tif (result.line) {\n\t\t\t\ttext += `\\nLine: ${result.line}`;\n\t\t\t}\n\t\t\treturn { content: [{ type: \"text\", text }] };\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `Error: ${(error as Error).message}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tisError: true,\n\t\t\t};\n\t\t}\n\t},\n);\n\nasync function main() {\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n}\n\nmain().catch(console.error);\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { findNodeByNameAndLine, getTypeInfo, loadProgram } from \"./core.js\";\nimport type { InferredTypeResult, Options } from \"./types.js\";\n\n// Re-export types\nexport type { Options, InferredTypeResult };\n\n// Re-export core utilities\nexport {\n\tfindFirstMatch,\n\tfindNearestTsconfig,\n\tfindNodeByNameAndLine,\n\tgetLineNumber,\n\tgetTypeInfo,\n\tloadProgram,\n} from \"./core.js\";\n\n/**\n * Infer the type of a function or variable in a TypeScript file\n *\n * @param file - Path to the TypeScript file\n * @param name - Name of the function/variable to inspect\n * @param options - Optional: project path (string) or options object with line and project\n * @returns The inferred type information\n * @throws Error if file not found or symbol not found\n *\n * @example\n * ```ts\n * import { inferType } from \"prinfer\";\n *\n * // By name only\n * const result = inferType(\"./src/utils.ts\", \"myFunction\");\n * console.log(result.signature);\n * // => \"(x: number, y: string) => boolean\"\n *\n * // By name and line number\n * const result2 = inferType(\"./src/utils.ts\", \"commandResult\", { line: 75 });\n * console.log(result2.signature);\n * // => \"Result<VaultAction[], CommandError>\"\n * ```\n */\nexport function inferType(\n\tfile: string,\n\tname: string,\n\toptions?: string | { line?: number; project?: string },\n): InferredTypeResult {\n\t// Normalize options for backward compatibility\n\tconst opts =\n\t\ttypeof options === \"string\" ? { project: options } : (options ?? {});\n\tconst { line, project } = opts;\n\n\tconst entryFileAbs = path.resolve(process.cwd(), file);\n\n\tif (!fs.existsSync(entryFileAbs)) {\n\t\tthrow new Error(`File not found: ${entryFileAbs}`);\n\t}\n\n\tconst program = loadProgram(entryFileAbs, project);\n\tconst sourceFile = program.getSourceFile(entryFileAbs);\n\n\tif (!sourceFile) {\n\t\tthrow new Error(\n\t\t\t`Could not load source file into the program (check tsconfig include/exclude): ${entryFileAbs}`,\n\t\t);\n\t}\n\n\tconst node = findNodeByNameAndLine(sourceFile, name, line);\n\tif (!node) {\n\t\tconst lineInfo = line !== undefined ? ` at line ${line}` : \"\";\n\t\tthrow new Error(\n\t\t\t`No symbol named \"${name}\"${lineInfo} found in ${entryFileAbs}`,\n\t\t);\n\t}\n\n\treturn getTypeInfo(program, node, sourceFile);\n}\n\n/**\n * Infer the type using an options object\n *\n * @param options - Options for type inference\n * @returns The inferred type information\n */\nexport function inferTypeFromOptions(options: Options): InferredTypeResult {\n\treturn inferType(options.file, options.name, {\n\t\tline: options.line,\n\t\tproject: options.project,\n\t});\n}\n","import path from \"node:path\";\nimport ts from \"typescript\";\nimport type { InferredTypeResult } from \"./types.js\";\n\n/**\n * Find the nearest tsconfig.json from a starting directory\n */\nexport function findNearestTsconfig(startDir: string): string | undefined {\n\treturn (\n\t\tts.findConfigFile(startDir, ts.sys.fileExists, \"tsconfig.json\") ??\n\t\tundefined\n\t);\n}\n\n/**\n * Load a TypeScript program from an entry file\n */\nexport function loadProgram(\n\tentryFileAbs: string,\n\tproject?: string,\n): ts.Program {\n\tconst fileDir = path.dirname(entryFileAbs);\n\tconst tsconfigPath = project\n\t\t? path.resolve(process.cwd(), project)\n\t\t: findNearestTsconfig(fileDir);\n\n\tif (!tsconfigPath) {\n\t\t// Fallback: single-file program\n\t\treturn ts.createProgram([entryFileAbs], {\n\t\t\ttarget: ts.ScriptTarget.ES2022,\n\t\t\tmodule: ts.ModuleKind.ESNext,\n\t\t\tstrict: true,\n\t\t\tallowJs: true,\n\t\t\tcheckJs: false,\n\t\t\tmoduleResolution: ts.ModuleResolutionKind.Bundler,\n\t\t\tskipLibCheck: true,\n\t\t});\n\t}\n\n\tconst cfg = ts.readConfigFile(tsconfigPath, ts.sys.readFile);\n\tif (cfg.error) {\n\t\tthrow new Error(\n\t\t\tts.flattenDiagnosticMessageText(cfg.error.messageText, \"\\n\"),\n\t\t);\n\t}\n\n\tconst parsed = ts.parseJsonConfigFileContent(\n\t\tcfg.config,\n\t\tts.sys,\n\t\tpath.dirname(tsconfigPath),\n\t);\n\treturn ts.createProgram({\n\t\trootNames: parsed.fileNames,\n\t\toptions: parsed.options,\n\t});\n}\n\nfunction isArrowOrFnExpr(\n\tn: ts.Node | undefined,\n): n is ts.ArrowFunction | ts.FunctionExpression {\n\treturn !!n && (ts.isArrowFunction(n) || ts.isFunctionExpression(n));\n}\n\nfunction nodeNameText(\n\tn: ts.PropertyName | ts.BindingName | undefined,\n): string | undefined {\n\tif (!n) return undefined;\n\tif (ts.isIdentifier(n)) return n.text;\n\tif (ts.isStringLiteral(n)) return n.text;\n\tif (ts.isNumericLiteral(n)) return n.text;\n\treturn undefined; // ignore computed names etc.\n}\n\nfunction isFunctionLikeNamed(node: ts.Node, name: string): boolean {\n\t// function foo() {}\n\tif (ts.isFunctionDeclaration(node) && node.name?.text === name) return true;\n\n\t// const foo = () => {} / function() {}\n\tif (\n\t\tts.isVariableDeclaration(node) &&\n\t\tts.isIdentifier(node.name) &&\n\t\tnode.name.text === name\n\t) {\n\t\treturn isArrowOrFnExpr(node.initializer);\n\t}\n\n\t// class C { foo() {} } / interface signatures\n\tif (\n\t\t(ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) &&\n\t\tnodeNameText(node.name) === name\n\t) {\n\t\treturn true;\n\t}\n\n\t// object literal { foo() {} } via MethodDeclaration inside object literal is also MethodDeclaration\n\t// property assignment: { foo: () => {} }\n\tif (ts.isPropertyAssignment(node) && nodeNameText(node.name) === name) {\n\t\treturn isArrowOrFnExpr(node.initializer);\n\t}\n\n\treturn false;\n}\n\n/**\n * Check if a node is any variable declaration with the given name\n */\nfunction isVariableNamed(node: ts.Node, name: string): boolean {\n\tif (\n\t\tts.isVariableDeclaration(node) &&\n\t\tts.isIdentifier(node.name) &&\n\t\tnode.name.text === name\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * Check if a node matches the given name (function-like or variable)\n */\nfunction isNamedNode(node: ts.Node, name: string): boolean {\n\treturn isFunctionLikeNamed(node, name) || isVariableNamed(node, name);\n}\n\n/**\n * Get the 1-based line number for a node\n */\nexport function getLineNumber(\n\tsourceFile: ts.SourceFile,\n\tnode: ts.Node,\n): number {\n\tconst { line } = sourceFile.getLineAndCharacterOfPosition(\n\t\tnode.getStart(sourceFile),\n\t);\n\treturn line + 1;\n}\n\n/**\n * Find the first function-like node with the given name in a source file\n */\nexport function findFirstMatch(\n\tsourceFile: ts.SourceFile,\n\tname: string,\n): ts.Node | undefined {\n\tlet found: ts.Node | undefined;\n\n\tconst visit = (node: ts.Node) => {\n\t\tif (found) return;\n\t\tif (isFunctionLikeNamed(node, name)) {\n\t\t\tfound = node;\n\t\t\treturn;\n\t\t}\n\t\tts.forEachChild(node, visit);\n\t};\n\n\tvisit(sourceFile);\n\treturn found;\n}\n\n/**\n * Find a node by name and optionally by line number\n */\nexport function findNodeByNameAndLine(\n\tsourceFile: ts.SourceFile,\n\tname: string,\n\tline?: number,\n): ts.Node | undefined {\n\tlet found: ts.Node | undefined;\n\n\tconst visit = (node: ts.Node) => {\n\t\tif (found) return;\n\t\tif (isNamedNode(node, name)) {\n\t\t\tif (line !== undefined) {\n\t\t\t\tconst nodeLine = getLineNumber(sourceFile, node);\n\t\t\t\tif (nodeLine === line) {\n\t\t\t\t\tfound = node;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfound = node;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tts.forEachChild(node, visit);\n\t};\n\n\tvisit(sourceFile);\n\treturn found;\n}\n\n/**\n * Get type information for a node\n */\nexport function getTypeInfo(\n\tprogram: ts.Program,\n\tnode: ts.Node,\n\tsourceFile?: ts.SourceFile,\n): InferredTypeResult {\n\tconst checker = program.getTypeChecker();\n\tconst sf = sourceFile ?? node.getSourceFile();\n\tconst line = getLineNumber(sf, node);\n\n\tlet sig: ts.Signature | undefined;\n\n\t// Prefer getting the signature from a declaration/expression directly\n\tif (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t} else if (ts.isVariableDeclaration(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isPropertyAssignment(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isMethodSignature(node)) {\n\t\t// interfaces/types\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t}\n\n\tconst flags = ts.TypeFormatFlags.NoTruncation;\n\n\tif (sig) {\n\t\tconst signature = checker.signatureToString(sig, undefined, flags);\n\t\tconst ret = checker.getReturnTypeOfSignature(sig);\n\t\tconst returnType = checker.typeToString(ret, undefined, flags);\n\t\treturn { signature, returnType, line };\n\t}\n\n\t// Fallback: type at the name location\n\tconst nodeWithName = node as unknown as { name?: ts.Node };\n\tlet nameNode: ts.Node = node;\n\tif (nodeWithName.name && ts.isIdentifier(nodeWithName.name)) {\n\t\tnameNode = nodeWithName.name;\n\t}\n\n\tconst t = checker.getTypeAtLocation(nameNode);\n\treturn { signature: checker.typeToString(t, undefined, flags), line };\n}\n"],"mappings":"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","names":["path","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/mcp.ts","../src/index.ts","../src/core.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { hover } from \"./index.js\";\n\nconst HELP = `\nprinfer-mcp - MCP server for TypeScript type inference\n\nThis is an MCP (Model Context Protocol) server. It's designed to be run\nby Claude Code, not directly from the command line.\n\nSetup:\n Run 'prinfer setup' to configure Claude Code automatically.\n\nManual setup:\n Run: claude mcp add prinfer node /path/to/prinfer-mcp\n\nProvided tools:\n hover(file, line, column, include_docs?, project?)\n Get TypeScript type information at a specific position.\n\nSee also:\n prinfer --help CLI for direct type inspection\n`.trim();\n\nif (process.argv.includes(\"--help\") || process.argv.includes(\"-h\")) {\n\tconsole.log(HELP);\n\tprocess.exit(0);\n}\n\nconst server = new McpServer({\n\tname: \"prinfer\",\n\tversion: \"0.3.0\",\n});\n\nserver.tool(\n\t\"hover\",\n\t\"Get TypeScript type information at a specific position in a file. Returns the type signature, return type, documentation, and symbol kind.\",\n\t{\n\t\tfile: z.string().describe(\"Path to the TypeScript file\"),\n\t\tline: z.number().describe(\"1-based line number\"),\n\t\tcolumn: z.number().describe(\"1-based column (character position)\"),\n\t\tinclude_docs: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe(\"Include JSDoc/TSDoc documentation\"),\n\t\tproject: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe(\"Optional path to tsconfig.json\"),\n\t},\n\tasync ({ file, line, column, include_docs, project }) => {\n\t\ttry {\n\t\t\tconst result = hover(file, line, column, { include_docs, project });\n\t\t\tlet text = `Type: ${result.signature}`;\n\t\t\tif (result.returnType) {\n\t\t\t\ttext += `\\nReturns: ${result.returnType}`;\n\t\t\t}\n\t\t\tif (result.name) {\n\t\t\t\ttext += `\\nName: ${result.name}`;\n\t\t\t}\n\t\t\ttext += `\\nKind: ${result.kind}`;\n\t\t\ttext += `\\nPosition: ${result.line}:${result.column}`;\n\t\t\tif (result.documentation) {\n\t\t\t\ttext += `\\nDocumentation: ${result.documentation}`;\n\t\t\t}\n\t\t\treturn { content: [{ type: \"text\", text }] };\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `Error: ${(error as Error).message}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tisError: true,\n\t\t\t};\n\t\t}\n\t},\n);\n\nasync function main() {\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n}\n\nmain().catch(console.error);\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport {\n\tfindNodeAtPosition,\n\tfindNodeByNameAndLine,\n\tgetHoverInfo,\n\tgetTypeInfo,\n\tloadProgram,\n} from \"./core.js\";\nimport type {\n\tHoverOptions,\n\tHoverResult,\n\tInferredTypeResult,\n\tOptions,\n} from \"./types.js\";\n\n// Re-export types\nexport type { HoverOptions, HoverResult, InferredTypeResult, Options };\n\n// Re-export core utilities\nexport {\n\tfindFirstMatch,\n\tfindNearestTsconfig,\n\tfindNodeAtPosition,\n\tfindNodeByNameAndLine,\n\tgetDocumentation,\n\tgetHoverInfo,\n\tgetLineNumber,\n\tgetTypeInfo,\n\tloadProgram,\n} from \"./core.js\";\n\n/**\n * Infer the type of a function or variable in a TypeScript file\n *\n * @param file - Path to the TypeScript file\n * @param name - Name of the function/variable to inspect\n * @param options - Optional: project path (string) or options object with line and project\n * @returns The inferred type information\n * @throws Error if file not found or symbol not found\n *\n * @example\n * ```ts\n * import { inferType } from \"prinfer\";\n *\n * // By name only\n * const result = inferType(\"./src/utils.ts\", \"myFunction\");\n * console.log(result.signature);\n * // => \"(x: number, y: string) => boolean\"\n *\n * // By name and line number\n * const result2 = inferType(\"./src/utils.ts\", \"commandResult\", { line: 75 });\n * console.log(result2.signature);\n * // => \"Result<VaultAction[], CommandError>\"\n * ```\n */\nexport function inferType(\n\tfile: string,\n\tname: string,\n\toptions?: string | { line?: number; project?: string },\n): InferredTypeResult {\n\t// Normalize options for backward compatibility\n\tconst opts =\n\t\ttypeof options === \"string\" ? { project: options } : (options ?? {});\n\tconst { line, project } = opts;\n\n\tconst entryFileAbs = path.resolve(process.cwd(), file);\n\n\tif (!fs.existsSync(entryFileAbs)) {\n\t\tthrow new Error(`File not found: ${entryFileAbs}`);\n\t}\n\n\tconst program = loadProgram(entryFileAbs, project);\n\tconst sourceFile = program.getSourceFile(entryFileAbs);\n\n\tif (!sourceFile) {\n\t\tthrow new Error(\n\t\t\t`Could not load source file into the program (check tsconfig include/exclude): ${entryFileAbs}`,\n\t\t);\n\t}\n\n\tconst node = findNodeByNameAndLine(sourceFile, name, line);\n\tif (!node) {\n\t\tconst lineInfo = line !== undefined ? ` at line ${line}` : \"\";\n\t\tthrow new Error(\n\t\t\t`No symbol named \"${name}\"${lineInfo} found in ${entryFileAbs}`,\n\t\t);\n\t}\n\n\treturn getTypeInfo(program, node, sourceFile);\n}\n\n/**\n * Infer the type using an options object\n *\n * @param options - Options for type inference\n * @returns The inferred type information\n */\nexport function inferTypeFromOptions(options: Options): InferredTypeResult {\n\treturn inferType(options.file, options.name, {\n\t\tline: options.line,\n\t\tproject: options.project,\n\t});\n}\n\n/**\n * Get type information at a specific position in a TypeScript file\n *\n * @param file - Path to the TypeScript file\n * @param line - 1-based line number\n * @param column - 1-based column number\n * @param options - Optional hover options (project path, include_docs)\n * @returns The hover information at the position\n * @throws Error if file not found or no symbol at position\n *\n * @example\n * ```ts\n * import { hover } from \"prinfer\";\n *\n * const result = hover(\"./src/utils.ts\", 75, 10);\n * console.log(result.signature);\n * // => \"(x: number) => string\"\n *\n * // With documentation\n * const result2 = hover(\"./src/utils.ts\", 75, 10, { include_docs: true });\n * console.log(result2.documentation);\n * // => \"Formats a number as a string\"\n * ```\n */\nexport function hover(\n\tfile: string,\n\tline: number,\n\tcolumn: number,\n\toptions?: HoverOptions,\n): HoverResult {\n\tconst { project, include_docs = false } = options ?? {};\n\n\tconst entryFileAbs = path.resolve(process.cwd(), file);\n\n\tif (!fs.existsSync(entryFileAbs)) {\n\t\tthrow new Error(`File not found: ${entryFileAbs}`);\n\t}\n\n\tconst program = loadProgram(entryFileAbs, project);\n\tconst sourceFile = program.getSourceFile(entryFileAbs);\n\n\tif (!sourceFile) {\n\t\tthrow new Error(\n\t\t\t`Could not load source file into the program (check tsconfig include/exclude): ${entryFileAbs}`,\n\t\t);\n\t}\n\n\tconst node = findNodeAtPosition(sourceFile, line, column);\n\tif (!node) {\n\t\tthrow new Error(`No symbol found at ${entryFileAbs}:${line}:${column}`);\n\t}\n\n\treturn getHoverInfo(program, node, sourceFile, include_docs);\n}\n","import path from \"node:path\";\nimport ts from \"typescript\";\nimport type { HoverResult, InferredTypeResult } from \"./types.js\";\n\n/**\n * Find the nearest tsconfig.json from a starting directory\n */\nexport function findNearestTsconfig(startDir: string): string | undefined {\n\treturn (\n\t\tts.findConfigFile(startDir, ts.sys.fileExists, \"tsconfig.json\") ??\n\t\tundefined\n\t);\n}\n\n/**\n * Load a TypeScript program from an entry file\n */\nexport function loadProgram(\n\tentryFileAbs: string,\n\tproject?: string,\n): ts.Program {\n\tconst fileDir = path.dirname(entryFileAbs);\n\tconst tsconfigPath = project\n\t\t? path.resolve(process.cwd(), project)\n\t\t: findNearestTsconfig(fileDir);\n\n\tif (!tsconfigPath) {\n\t\t// Fallback: single-file program\n\t\treturn ts.createProgram([entryFileAbs], {\n\t\t\ttarget: ts.ScriptTarget.ES2022,\n\t\t\tmodule: ts.ModuleKind.ESNext,\n\t\t\tstrict: true,\n\t\t\tallowJs: true,\n\t\t\tcheckJs: false,\n\t\t\tmoduleResolution: ts.ModuleResolutionKind.Bundler,\n\t\t\tskipLibCheck: true,\n\t\t});\n\t}\n\n\tconst cfg = ts.readConfigFile(tsconfigPath, ts.sys.readFile);\n\tif (cfg.error) {\n\t\tthrow new Error(\n\t\t\tts.flattenDiagnosticMessageText(cfg.error.messageText, \"\\n\"),\n\t\t);\n\t}\n\n\tconst parsed = ts.parseJsonConfigFileContent(\n\t\tcfg.config,\n\t\tts.sys,\n\t\tpath.dirname(tsconfigPath),\n\t);\n\treturn ts.createProgram({\n\t\trootNames: parsed.fileNames,\n\t\toptions: parsed.options,\n\t});\n}\n\nfunction isArrowOrFnExpr(\n\tn: ts.Node | undefined,\n): n is ts.ArrowFunction | ts.FunctionExpression {\n\treturn !!n && (ts.isArrowFunction(n) || ts.isFunctionExpression(n));\n}\n\nfunction nodeNameText(\n\tn: ts.PropertyName | ts.BindingName | undefined,\n): string | undefined {\n\tif (!n) return undefined;\n\tif (ts.isIdentifier(n)) return n.text;\n\tif (ts.isStringLiteral(n)) return n.text;\n\tif (ts.isNumericLiteral(n)) return n.text;\n\treturn undefined; // ignore computed names etc.\n}\n\nfunction isFunctionLikeNamed(node: ts.Node, name: string): boolean {\n\t// function foo() {}\n\tif (ts.isFunctionDeclaration(node) && node.name?.text === name) return true;\n\n\t// const foo = () => {} / function() {}\n\tif (\n\t\tts.isVariableDeclaration(node) &&\n\t\tts.isIdentifier(node.name) &&\n\t\tnode.name.text === name\n\t) {\n\t\treturn isArrowOrFnExpr(node.initializer);\n\t}\n\n\t// class C { foo() {} } / interface signatures\n\tif (\n\t\t(ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) &&\n\t\tnodeNameText(node.name) === name\n\t) {\n\t\treturn true;\n\t}\n\n\t// object literal { foo() {} } via MethodDeclaration inside object literal is also MethodDeclaration\n\t// property assignment: { foo: () => {} }\n\tif (ts.isPropertyAssignment(node) && nodeNameText(node.name) === name) {\n\t\treturn isArrowOrFnExpr(node.initializer);\n\t}\n\n\treturn false;\n}\n\n/**\n * Check if a node is any variable declaration with the given name\n */\nfunction isVariableNamed(node: ts.Node, name: string): boolean {\n\tif (\n\t\tts.isVariableDeclaration(node) &&\n\t\tts.isIdentifier(node.name) &&\n\t\tnode.name.text === name\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * Check if a node matches the given name (function-like or variable)\n */\nfunction isNamedNode(node: ts.Node, name: string): boolean {\n\treturn isFunctionLikeNamed(node, name) || isVariableNamed(node, name);\n}\n\n/**\n * Check if a node is a call expression with the given name\n */\nfunction isCallExpressionNamed(node: ts.Node, name: string): boolean {\n\tif (!ts.isCallExpression(node)) return false;\n\tconst expr = node.expression;\n\n\t// Direct call: foo()\n\tif (ts.isIdentifier(expr) && expr.text === name) return true;\n\n\t// Property access: this.foo() or obj.foo()\n\tif (ts.isPropertyAccessExpression(expr) && expr.name.text === name)\n\t\treturn true;\n\n\treturn false;\n}\n\n/**\n * Get the 1-based line number for a node\n */\nexport function getLineNumber(\n\tsourceFile: ts.SourceFile,\n\tnode: ts.Node,\n): number {\n\tconst { line } = sourceFile.getLineAndCharacterOfPosition(\n\t\tnode.getStart(sourceFile),\n\t);\n\treturn line + 1;\n}\n\n/**\n * Find the first function-like node with the given name in a source file\n */\nexport function findFirstMatch(\n\tsourceFile: ts.SourceFile,\n\tname: string,\n): ts.Node | undefined {\n\tlet found: ts.Node | undefined;\n\n\tconst visit = (node: ts.Node) => {\n\t\tif (found) return;\n\t\tif (isFunctionLikeNamed(node, name)) {\n\t\t\tfound = node;\n\t\t\treturn;\n\t\t}\n\t\tts.forEachChild(node, visit);\n\t};\n\n\tvisit(sourceFile);\n\treturn found;\n}\n\n/**\n * Find a node by name and optionally by line number\n */\nexport function findNodeByNameAndLine(\n\tsourceFile: ts.SourceFile,\n\tname: string,\n\tline?: number,\n): ts.Node | undefined {\n\tlet found: ts.Node | undefined;\n\n\tconst matchesLine = (node: ts.Node): boolean => {\n\t\tif (line === undefined) return true;\n\t\treturn getLineNumber(sourceFile, node) === line;\n\t};\n\n\tconst visit = (node: ts.Node) => {\n\t\tif (found) return;\n\n\t\t// Check declarations (existing logic)\n\t\tif (isNamedNode(node, name) && matchesLine(node)) {\n\t\t\tfound = node;\n\t\t\treturn;\n\t\t}\n\n\t\t// Check call expressions (new)\n\t\tif (isCallExpressionNamed(node, name) && matchesLine(node)) {\n\t\t\tfound = node;\n\t\t\treturn;\n\t\t}\n\n\t\tts.forEachChild(node, visit);\n\t};\n\n\tvisit(sourceFile);\n\treturn found;\n}\n\n/**\n * Get type information for a node\n */\nexport function getTypeInfo(\n\tprogram: ts.Program,\n\tnode: ts.Node,\n\tsourceFile?: ts.SourceFile,\n): InferredTypeResult {\n\tconst checker = program.getTypeChecker();\n\tconst sf = sourceFile ?? node.getSourceFile();\n\tconst line = getLineNumber(sf, node);\n\tconst flags = ts.TypeFormatFlags.NoTruncation;\n\n\t// Handle call expressions - get instantiated signature\n\tif (ts.isCallExpression(node)) {\n\t\tconst sig = checker.getResolvedSignature(node);\n\t\tif (sig) {\n\t\t\tconst signature = checker.signatureToString(sig, undefined, flags);\n\t\t\tconst ret = checker.getReturnTypeOfSignature(sig);\n\t\t\tconst returnType = checker.typeToString(ret, undefined, flags);\n\t\t\treturn { signature, returnType, line };\n\t\t}\n\t\t// Fallback: get type of the call result\n\t\tconst t = checker.getTypeAtLocation(node);\n\t\treturn { signature: checker.typeToString(t, undefined, flags), line };\n\t}\n\n\tlet sig: ts.Signature | undefined;\n\n\t// Prefer getting the signature from a declaration/expression directly\n\tif (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t} else if (ts.isVariableDeclaration(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isPropertyAssignment(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isMethodSignature(node)) {\n\t\t// interfaces/types\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t}\n\n\tif (sig) {\n\t\tconst signature = checker.signatureToString(sig, undefined, flags);\n\t\tconst ret = checker.getReturnTypeOfSignature(sig);\n\t\tconst returnType = checker.typeToString(ret, undefined, flags);\n\t\treturn { signature, returnType, line };\n\t}\n\n\t// Fallback: type at the name location\n\tconst nodeWithName = node as unknown as { name?: ts.Node };\n\tlet nameNode: ts.Node = node;\n\tif (nodeWithName.name && ts.isIdentifier(nodeWithName.name)) {\n\t\tnameNode = nodeWithName.name;\n\t}\n\n\tconst t = checker.getTypeAtLocation(nameNode);\n\treturn { signature: checker.typeToString(t, undefined, flags), line };\n}\n\n/**\n * Find the most specific node containing a position by walking the AST\n */\nfunction findSmallestNodeAtPosition(\n\tsourceFile: ts.SourceFile,\n\tposition: number,\n): ts.Node | undefined {\n\tlet result: ts.Node | undefined;\n\n\tfunction visit(node: ts.Node): void {\n\t\tconst start = node.getStart(sourceFile);\n\t\tconst end = node.getEnd();\n\n\t\t// Position must be within this node's range\n\t\tif (position < start || position >= end) {\n\t\t\treturn;\n\t\t}\n\n\t\t// This node contains the position - check if it's more specific than current result\n\t\tif (\n\t\t\t!result ||\n\t\t\tnode.getWidth(sourceFile) <= result.getWidth(sourceFile)\n\t\t) {\n\t\t\tresult = node;\n\t\t}\n\n\t\t// Continue to check children for more specific nodes\n\t\tts.forEachChild(node, visit);\n\t}\n\n\tvisit(sourceFile);\n\treturn result;\n}\n\n/**\n * Walk up from a token to find the most useful node for hover info\n */\nfunction findHoverableAncestor(\n\tsourceFile: ts.SourceFile,\n\tposition: number,\n): ts.Node | undefined {\n\tconst smallestNode = findSmallestNodeAtPosition(sourceFile, position);\n\tif (!smallestNode) return undefined;\n\n\t// Walk up the tree to find the most useful hoverable node\n\tlet bestMatch: ts.Node | undefined = smallestNode;\n\n\t// Visit ancestors\n\tfunction visit(n: ts.Node): boolean {\n\t\tconst start = n.getStart(sourceFile);\n\t\tconst end = n.getEnd();\n\n\t\tif (position < start || position >= end) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if this is a call expression with our node as the callee\n\t\tif (ts.isCallExpression(n)) {\n\t\t\tconst expr = n.expression;\n\t\t\t// Check if position is on the function name part\n\t\t\tif (ts.isIdentifier(expr)) {\n\t\t\t\tif (\n\t\t\t\t\tposition >= expr.getStart(sourceFile) &&\n\t\t\t\t\tposition < expr.getEnd()\n\t\t\t\t) {\n\t\t\t\t\tbestMatch = n;\n\t\t\t\t}\n\t\t\t} else if (ts.isPropertyAccessExpression(expr)) {\n\t\t\t\tif (\n\t\t\t\t\tposition >= expr.name.getStart(sourceFile) &&\n\t\t\t\t\tposition < expr.name.getEnd()\n\t\t\t\t) {\n\t\t\t\t\tbestMatch = n;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If this is a declaration and the position is on its name, use this declaration\n\t\tif (ts.isFunctionDeclaration(n) && n.name) {\n\t\t\tif (\n\t\t\t\tposition >= n.name.getStart(sourceFile) &&\n\t\t\t\tposition < n.name.getEnd()\n\t\t\t) {\n\t\t\t\tbestMatch = n;\n\t\t\t}\n\t\t}\n\t\tif (ts.isVariableDeclaration(n) && ts.isIdentifier(n.name)) {\n\t\t\tif (\n\t\t\t\tposition >= n.name.getStart(sourceFile) &&\n\t\t\t\tposition < n.name.getEnd()\n\t\t\t) {\n\t\t\t\tbestMatch = n;\n\t\t\t}\n\t\t}\n\t\tif (\n\t\t\t(ts.isMethodDeclaration(n) || ts.isMethodSignature(n)) &&\n\t\t\tts.isIdentifier(n.name)\n\t\t) {\n\t\t\tif (\n\t\t\t\tposition >= n.name.getStart(sourceFile) &&\n\t\t\t\tposition < n.name.getEnd()\n\t\t\t) {\n\t\t\t\tbestMatch = n;\n\t\t\t}\n\t\t}\n\t\tif (ts.isClassDeclaration(n) && n.name) {\n\t\t\tif (\n\t\t\t\tposition >= n.name.getStart(sourceFile) &&\n\t\t\t\tposition < n.name.getEnd()\n\t\t\t) {\n\t\t\t\tbestMatch = n;\n\t\t\t}\n\t\t}\n\t\tif (ts.isInterfaceDeclaration(n) && n.name) {\n\t\t\tif (\n\t\t\t\tposition >= n.name.getStart(sourceFile) &&\n\t\t\t\tposition < n.name.getEnd()\n\t\t\t) {\n\t\t\t\tbestMatch = n;\n\t\t\t}\n\t\t}\n\n\t\tts.forEachChild(n, visit);\n\t\treturn true;\n\t}\n\n\tvisit(sourceFile);\n\treturn bestMatch;\n}\n\n/**\n * Find the node at a specific position (1-based line and column)\n */\nexport function findNodeAtPosition(\n\tsourceFile: ts.SourceFile,\n\tline: number,\n\tcolumn: number,\n): ts.Node | undefined {\n\t// Validate line/column bounds\n\tconst lineCount = sourceFile.getLineStarts().length;\n\tif (line < 1 || line > lineCount) {\n\t\treturn undefined;\n\t}\n\n\tconst lineStart = sourceFile.getLineStarts()[line - 1];\n\tconst lineEnd =\n\t\tline < lineCount\n\t\t\t? sourceFile.getLineStarts()[line]\n\t\t\t: sourceFile.getEnd();\n\tconst lineLength = lineEnd - lineStart;\n\n\tif (column < 1 || column > lineLength + 1) {\n\t\treturn undefined;\n\t}\n\n\t// Convert 1-based line/column to 0-based position\n\tconst position = sourceFile.getPositionOfLineAndCharacter(\n\t\tline - 1,\n\t\tcolumn - 1,\n\t);\n\n\treturn findHoverableAncestor(sourceFile, position);\n}\n\n/**\n * Get the symbol kind as a string\n */\nfunction getSymbolKind(node: ts.Node): string {\n\tif (ts.isFunctionDeclaration(node)) return \"function\";\n\tif (ts.isArrowFunction(node)) return \"function\";\n\tif (ts.isFunctionExpression(node)) return \"function\";\n\tif (ts.isMethodDeclaration(node)) return \"method\";\n\tif (ts.isMethodSignature(node)) return \"method\";\n\tif (ts.isVariableDeclaration(node)) {\n\t\tconst init = node.initializer;\n\t\tif (\n\t\t\tinit &&\n\t\t\t(ts.isArrowFunction(init) || ts.isFunctionExpression(init))\n\t\t) {\n\t\t\treturn \"function\";\n\t\t}\n\t\treturn \"variable\";\n\t}\n\tif (ts.isParameter(node)) return \"parameter\";\n\tif (ts.isPropertyDeclaration(node)) return \"property\";\n\tif (ts.isPropertySignature(node)) return \"property\";\n\tif (ts.isPropertyAccessExpression(node)) return \"property\";\n\tif (ts.isCallExpression(node)) return \"call\";\n\tif (ts.isTypeAliasDeclaration(node)) return \"type\";\n\tif (ts.isInterfaceDeclaration(node)) return \"interface\";\n\tif (ts.isClassDeclaration(node)) return \"class\";\n\tif (ts.isIdentifier(node)) return \"identifier\";\n\treturn \"unknown\";\n}\n\n/**\n * Get the name of a node if it has one\n */\nfunction getNodeName(node: ts.Node): string | undefined {\n\tif (ts.isFunctionDeclaration(node) && node.name) {\n\t\treturn node.name.text;\n\t}\n\tif (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {\n\t\treturn node.name.text;\n\t}\n\tif (\n\t\t(ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) &&\n\t\tts.isIdentifier(node.name)\n\t) {\n\t\treturn node.name.text;\n\t}\n\tif (ts.isPropertyAccessExpression(node)) {\n\t\treturn node.name.text;\n\t}\n\tif (ts.isCallExpression(node)) {\n\t\tconst expr = node.expression;\n\t\tif (ts.isIdentifier(expr)) return expr.text;\n\t\tif (ts.isPropertyAccessExpression(expr)) return expr.name.text;\n\t}\n\tif (ts.isParameter(node) && ts.isIdentifier(node.name)) {\n\t\treturn node.name.text;\n\t}\n\tif (ts.isIdentifier(node)) {\n\t\treturn node.text;\n\t}\n\tif (\n\t\tts.isTypeAliasDeclaration(node) ||\n\t\tts.isInterfaceDeclaration(node) ||\n\t\tts.isClassDeclaration(node)\n\t) {\n\t\treturn node.name?.text;\n\t}\n\treturn undefined;\n}\n\n/**\n * Get documentation from a symbol\n */\nexport function getDocumentation(\n\tchecker: ts.TypeChecker,\n\tsymbol: ts.Symbol | undefined,\n): string | undefined {\n\tif (!symbol) return undefined;\n\n\tconst docs = symbol.getDocumentationComment(checker);\n\tif (docs.length === 0) return undefined;\n\n\treturn ts.displayPartsToString(docs);\n}\n\n/**\n * Get hover information at a specific position\n */\nexport function getHoverInfo(\n\tprogram: ts.Program,\n\tnode: ts.Node,\n\tsourceFile: ts.SourceFile,\n\tincludeDocs: boolean,\n): HoverResult {\n\tconst checker = program.getTypeChecker();\n\tconst sf = sourceFile;\n\tconst { line, character } = sf.getLineAndCharacterOfPosition(\n\t\tnode.getStart(sf),\n\t);\n\tconst flags = ts.TypeFormatFlags.NoTruncation;\n\n\tconst kind = getSymbolKind(node);\n\tconst name = getNodeName(node);\n\n\t// Get symbol for documentation\n\tlet symbol: ts.Symbol | undefined;\n\tif (ts.isCallExpression(node)) {\n\t\t// For calls, get symbol from the expression\n\t\tconst expr = node.expression;\n\t\tif (ts.isPropertyAccessExpression(expr)) {\n\t\t\tsymbol = checker.getSymbolAtLocation(expr.name);\n\t\t} else {\n\t\t\tsymbol = checker.getSymbolAtLocation(expr);\n\t\t}\n\t} else {\n\t\tconst nodeWithName = node as unknown as { name?: ts.Node };\n\t\tif (nodeWithName.name) {\n\t\t\tsymbol = checker.getSymbolAtLocation(nodeWithName.name);\n\t\t} else {\n\t\t\tsymbol = checker.getSymbolAtLocation(node);\n\t\t}\n\t}\n\n\tconst documentation = includeDocs\n\t\t? getDocumentation(checker, symbol)\n\t\t: undefined;\n\n\t// Handle call expressions - get instantiated signature\n\tif (ts.isCallExpression(node)) {\n\t\tconst sig = checker.getResolvedSignature(node);\n\t\tif (sig) {\n\t\t\tconst signature = checker.signatureToString(sig, undefined, flags);\n\t\t\tconst ret = checker.getReturnTypeOfSignature(sig);\n\t\t\tconst returnType = checker.typeToString(ret, undefined, flags);\n\t\t\treturn {\n\t\t\t\tsignature,\n\t\t\t\treturnType,\n\t\t\t\tline: line + 1,\n\t\t\t\tcolumn: character + 1,\n\t\t\t\tdocumentation,\n\t\t\t\tkind,\n\t\t\t\tname,\n\t\t\t};\n\t\t}\n\t\t// Fallback: get type of the call result\n\t\tconst t = checker.getTypeAtLocation(node);\n\t\treturn {\n\t\t\tsignature: checker.typeToString(t, undefined, flags),\n\t\t\tline: line + 1,\n\t\t\tcolumn: character + 1,\n\t\t\tdocumentation,\n\t\t\tkind,\n\t\t\tname,\n\t\t};\n\t}\n\n\tlet sig: ts.Signature | undefined;\n\n\t// Prefer getting the signature from a declaration/expression directly\n\tif (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t} else if (ts.isVariableDeclaration(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isPropertyAssignment(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isMethodSignature(node)) {\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t}\n\n\tif (sig) {\n\t\tconst signature = checker.signatureToString(sig, undefined, flags);\n\t\tconst ret = checker.getReturnTypeOfSignature(sig);\n\t\tconst returnType = checker.typeToString(ret, undefined, flags);\n\t\treturn {\n\t\t\tsignature,\n\t\t\treturnType,\n\t\t\tline: line + 1,\n\t\t\tcolumn: character + 1,\n\t\t\tdocumentation,\n\t\t\tkind,\n\t\t\tname,\n\t\t};\n\t}\n\n\t// Fallback: type at the node location\n\tconst nodeWithName = node as unknown as { name?: ts.Node };\n\tlet targetNode: ts.Node = node;\n\tif (nodeWithName.name && ts.isIdentifier(nodeWithName.name)) {\n\t\ttargetNode = nodeWithName.name;\n\t}\n\n\tconst t = checker.getTypeAtLocation(targetNode);\n\treturn {\n\t\tsignature: checker.typeToString(t, undefined, flags),\n\t\tline: line + 1,\n\t\tcolumn: character + 1,\n\t\tdocumentation,\n\t\tkind,\n\t\tname,\n\t};\n}\n"],"mappings":"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","names":["path","nodeWithName","sig","t","path"]}
|