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/dist/mcp.cjs CHANGED
@@ -71,66 +71,203 @@ function loadProgram(entryFileAbs, project) {
71
71
  function isArrowOrFnExpr(n) {
72
72
  return !!n && (import_typescript.default.isArrowFunction(n) || import_typescript.default.isFunctionExpression(n));
73
73
  }
74
- function nodeNameText(n) {
75
- if (!n) return void 0;
76
- if (import_typescript.default.isIdentifier(n)) return n.text;
77
- if (import_typescript.default.isStringLiteral(n)) return n.text;
78
- if (import_typescript.default.isNumericLiteral(n)) return n.text;
79
- return void 0;
80
- }
81
- function isFunctionLikeNamed(node, name) {
82
- if (import_typescript.default.isFunctionDeclaration(node) && node.name?.text === name) return true;
83
- if (import_typescript.default.isVariableDeclaration(node) && import_typescript.default.isIdentifier(node.name) && node.name.text === name) {
84
- return isArrowOrFnExpr(node.initializer);
85
- }
86
- if ((import_typescript.default.isMethodDeclaration(node) || import_typescript.default.isMethodSignature(node)) && nodeNameText(node.name) === name) {
87
- return true;
88
- }
89
- if (import_typescript.default.isPropertyAssignment(node) && nodeNameText(node.name) === name) {
90
- return isArrowOrFnExpr(node.initializer);
74
+ function findSmallestNodeAtPosition(sourceFile, position) {
75
+ let result;
76
+ function visit(node) {
77
+ const start = node.getStart(sourceFile);
78
+ const end = node.getEnd();
79
+ if (position < start || position >= end) {
80
+ return;
81
+ }
82
+ if (!result || node.getWidth(sourceFile) <= result.getWidth(sourceFile)) {
83
+ result = node;
84
+ }
85
+ import_typescript.default.forEachChild(node, visit);
91
86
  }
92
- return false;
87
+ visit(sourceFile);
88
+ return result;
93
89
  }
94
- function isVariableNamed(node, name) {
95
- if (import_typescript.default.isVariableDeclaration(node) && import_typescript.default.isIdentifier(node.name) && node.name.text === name) {
90
+ function findHoverableAncestor(sourceFile, position) {
91
+ const smallestNode = findSmallestNodeAtPosition(sourceFile, position);
92
+ if (!smallestNode) return void 0;
93
+ let bestMatch = smallestNode;
94
+ function visit(n) {
95
+ const start = n.getStart(sourceFile);
96
+ const end = n.getEnd();
97
+ if (position < start || position >= end) {
98
+ return false;
99
+ }
100
+ if (import_typescript.default.isCallExpression(n)) {
101
+ const expr = n.expression;
102
+ if (import_typescript.default.isIdentifier(expr)) {
103
+ if (position >= expr.getStart(sourceFile) && position < expr.getEnd()) {
104
+ bestMatch = n;
105
+ }
106
+ } else if (import_typescript.default.isPropertyAccessExpression(expr)) {
107
+ if (position >= expr.name.getStart(sourceFile) && position < expr.name.getEnd()) {
108
+ bestMatch = n;
109
+ }
110
+ }
111
+ }
112
+ if (import_typescript.default.isFunctionDeclaration(n) && n.name) {
113
+ if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
114
+ bestMatch = n;
115
+ }
116
+ }
117
+ if (import_typescript.default.isVariableDeclaration(n) && import_typescript.default.isIdentifier(n.name)) {
118
+ if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
119
+ bestMatch = n;
120
+ }
121
+ }
122
+ if ((import_typescript.default.isMethodDeclaration(n) || import_typescript.default.isMethodSignature(n)) && import_typescript.default.isIdentifier(n.name)) {
123
+ if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
124
+ bestMatch = n;
125
+ }
126
+ }
127
+ if (import_typescript.default.isClassDeclaration(n) && n.name) {
128
+ if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
129
+ bestMatch = n;
130
+ }
131
+ }
132
+ if (import_typescript.default.isInterfaceDeclaration(n) && n.name) {
133
+ if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
134
+ bestMatch = n;
135
+ }
136
+ }
137
+ import_typescript.default.forEachChild(n, visit);
96
138
  return true;
97
139
  }
98
- return false;
99
- }
100
- function isNamedNode(node, name) {
101
- return isFunctionLikeNamed(node, name) || isVariableNamed(node, name);
140
+ visit(sourceFile);
141
+ return bestMatch;
102
142
  }
103
- function getLineNumber(sourceFile, node) {
104
- const { line } = sourceFile.getLineAndCharacterOfPosition(
105
- node.getStart(sourceFile)
143
+ function findNodeAtPosition(sourceFile, line, column) {
144
+ const lineCount = sourceFile.getLineStarts().length;
145
+ if (line < 1 || line > lineCount) {
146
+ return void 0;
147
+ }
148
+ const lineStart = sourceFile.getLineStarts()[line - 1];
149
+ const lineEnd = line < lineCount ? sourceFile.getLineStarts()[line] : sourceFile.getEnd();
150
+ const lineLength = lineEnd - lineStart;
151
+ if (column < 1 || column > lineLength + 1) {
152
+ return void 0;
153
+ }
154
+ const position = sourceFile.getPositionOfLineAndCharacter(
155
+ line - 1,
156
+ column - 1
106
157
  );
107
- return line + 1;
158
+ return findHoverableAncestor(sourceFile, position);
108
159
  }
109
- function findNodeByNameAndLine(sourceFile, name, line) {
110
- let found;
111
- const visit = (node) => {
112
- if (found) return;
113
- if (isNamedNode(node, name)) {
114
- if (line !== void 0) {
115
- const nodeLine = getLineNumber(sourceFile, node);
116
- if (nodeLine === line) {
117
- found = node;
118
- return;
119
- }
120
- } else {
121
- found = node;
122
- return;
123
- }
160
+ function getSymbolKind(node) {
161
+ if (import_typescript.default.isFunctionDeclaration(node)) return "function";
162
+ if (import_typescript.default.isArrowFunction(node)) return "function";
163
+ if (import_typescript.default.isFunctionExpression(node)) return "function";
164
+ if (import_typescript.default.isMethodDeclaration(node)) return "method";
165
+ if (import_typescript.default.isMethodSignature(node)) return "method";
166
+ if (import_typescript.default.isVariableDeclaration(node)) {
167
+ const init = node.initializer;
168
+ if (init && (import_typescript.default.isArrowFunction(init) || import_typescript.default.isFunctionExpression(init))) {
169
+ return "function";
124
170
  }
125
- import_typescript.default.forEachChild(node, visit);
126
- };
127
- visit(sourceFile);
128
- return found;
171
+ return "variable";
172
+ }
173
+ if (import_typescript.default.isParameter(node)) return "parameter";
174
+ if (import_typescript.default.isPropertyDeclaration(node)) return "property";
175
+ if (import_typescript.default.isPropertySignature(node)) return "property";
176
+ if (import_typescript.default.isPropertyAccessExpression(node)) return "property";
177
+ if (import_typescript.default.isCallExpression(node)) return "call";
178
+ if (import_typescript.default.isTypeAliasDeclaration(node)) return "type";
179
+ if (import_typescript.default.isInterfaceDeclaration(node)) return "interface";
180
+ if (import_typescript.default.isClassDeclaration(node)) return "class";
181
+ if (import_typescript.default.isIdentifier(node)) return "identifier";
182
+ return "unknown";
183
+ }
184
+ function getNodeName(node) {
185
+ if (import_typescript.default.isFunctionDeclaration(node) && node.name) {
186
+ return node.name.text;
187
+ }
188
+ if (import_typescript.default.isVariableDeclaration(node) && import_typescript.default.isIdentifier(node.name)) {
189
+ return node.name.text;
190
+ }
191
+ if ((import_typescript.default.isMethodDeclaration(node) || import_typescript.default.isMethodSignature(node)) && import_typescript.default.isIdentifier(node.name)) {
192
+ return node.name.text;
193
+ }
194
+ if (import_typescript.default.isPropertyAccessExpression(node)) {
195
+ return node.name.text;
196
+ }
197
+ if (import_typescript.default.isCallExpression(node)) {
198
+ const expr = node.expression;
199
+ if (import_typescript.default.isIdentifier(expr)) return expr.text;
200
+ if (import_typescript.default.isPropertyAccessExpression(expr)) return expr.name.text;
201
+ }
202
+ if (import_typescript.default.isParameter(node) && import_typescript.default.isIdentifier(node.name)) {
203
+ return node.name.text;
204
+ }
205
+ if (import_typescript.default.isIdentifier(node)) {
206
+ return node.text;
207
+ }
208
+ if (import_typescript.default.isTypeAliasDeclaration(node) || import_typescript.default.isInterfaceDeclaration(node) || import_typescript.default.isClassDeclaration(node)) {
209
+ return node.name?.text;
210
+ }
211
+ return void 0;
212
+ }
213
+ function getDocumentation(checker, symbol) {
214
+ if (!symbol) return void 0;
215
+ const docs = symbol.getDocumentationComment(checker);
216
+ if (docs.length === 0) return void 0;
217
+ return import_typescript.default.displayPartsToString(docs);
129
218
  }
130
- function getTypeInfo(program, node, sourceFile) {
219
+ function getHoverInfo(program, node, sourceFile, includeDocs) {
131
220
  const checker = program.getTypeChecker();
132
- const sf = sourceFile ?? node.getSourceFile();
133
- const line = getLineNumber(sf, node);
221
+ const sf = sourceFile;
222
+ const { line, character } = sf.getLineAndCharacterOfPosition(
223
+ node.getStart(sf)
224
+ );
225
+ const flags = import_typescript.default.TypeFormatFlags.NoTruncation;
226
+ const kind = getSymbolKind(node);
227
+ const name = getNodeName(node);
228
+ let symbol;
229
+ if (import_typescript.default.isCallExpression(node)) {
230
+ const expr = node.expression;
231
+ if (import_typescript.default.isPropertyAccessExpression(expr)) {
232
+ symbol = checker.getSymbolAtLocation(expr.name);
233
+ } else {
234
+ symbol = checker.getSymbolAtLocation(expr);
235
+ }
236
+ } else {
237
+ const nodeWithName2 = node;
238
+ if (nodeWithName2.name) {
239
+ symbol = checker.getSymbolAtLocation(nodeWithName2.name);
240
+ } else {
241
+ symbol = checker.getSymbolAtLocation(node);
242
+ }
243
+ }
244
+ const documentation = includeDocs ? getDocumentation(checker, symbol) : void 0;
245
+ if (import_typescript.default.isCallExpression(node)) {
246
+ const sig2 = checker.getResolvedSignature(node);
247
+ if (sig2) {
248
+ const signature = checker.signatureToString(sig2, void 0, flags);
249
+ const ret = checker.getReturnTypeOfSignature(sig2);
250
+ const returnType = checker.typeToString(ret, void 0, flags);
251
+ return {
252
+ signature,
253
+ returnType,
254
+ line: line + 1,
255
+ column: character + 1,
256
+ documentation,
257
+ kind,
258
+ name
259
+ };
260
+ }
261
+ const t2 = checker.getTypeAtLocation(node);
262
+ return {
263
+ signature: checker.typeToString(t2, void 0, flags),
264
+ line: line + 1,
265
+ column: character + 1,
266
+ documentation,
267
+ kind,
268
+ name
269
+ };
270
+ }
134
271
  let sig;
135
272
  if (import_typescript.default.isFunctionDeclaration(node) || import_typescript.default.isMethodDeclaration(node)) {
136
273
  sig = checker.getSignatureFromDeclaration(node) ?? void 0;
@@ -145,26 +282,39 @@ function getTypeInfo(program, node, sourceFile) {
145
282
  } else if (import_typescript.default.isMethodSignature(node)) {
146
283
  sig = checker.getSignatureFromDeclaration(node) ?? void 0;
147
284
  }
148
- const flags = import_typescript.default.TypeFormatFlags.NoTruncation;
149
285
  if (sig) {
150
286
  const signature = checker.signatureToString(sig, void 0, flags);
151
287
  const ret = checker.getReturnTypeOfSignature(sig);
152
288
  const returnType = checker.typeToString(ret, void 0, flags);
153
- return { signature, returnType, line };
289
+ return {
290
+ signature,
291
+ returnType,
292
+ line: line + 1,
293
+ column: character + 1,
294
+ documentation,
295
+ kind,
296
+ name
297
+ };
154
298
  }
155
299
  const nodeWithName = node;
156
- let nameNode = node;
300
+ let targetNode = node;
157
301
  if (nodeWithName.name && import_typescript.default.isIdentifier(nodeWithName.name)) {
158
- nameNode = nodeWithName.name;
302
+ targetNode = nodeWithName.name;
159
303
  }
160
- const t = checker.getTypeAtLocation(nameNode);
161
- return { signature: checker.typeToString(t, void 0, flags), line };
304
+ const t = checker.getTypeAtLocation(targetNode);
305
+ return {
306
+ signature: checker.typeToString(t, void 0, flags),
307
+ line: line + 1,
308
+ column: character + 1,
309
+ documentation,
310
+ kind,
311
+ name
312
+ };
162
313
  }
163
314
 
164
315
  // src/index.ts
165
- function inferType(file, name, options) {
166
- const opts = typeof options === "string" ? { project: options } : options ?? {};
167
- const { line, project } = opts;
316
+ function hover(file, line, column, options) {
317
+ const { project, include_docs = false } = options ?? {};
168
318
  const entryFileAbs = import_node_path2.default.resolve(process.cwd(), file);
169
319
  if (!import_node_fs.default.existsSync(entryFileAbs)) {
170
320
  throw new Error(`File not found: ${entryFileAbs}`);
@@ -176,14 +326,11 @@ function inferType(file, name, options) {
176
326
  `Could not load source file into the program (check tsconfig include/exclude): ${entryFileAbs}`
177
327
  );
178
328
  }
179
- const node = findNodeByNameAndLine(sourceFile, name, line);
329
+ const node = findNodeAtPosition(sourceFile, line, column);
180
330
  if (!node) {
181
- const lineInfo = line !== void 0 ? ` at line ${line}` : "";
182
- throw new Error(
183
- `No symbol named "${name}"${lineInfo} found in ${entryFileAbs}`
184
- );
331
+ throw new Error(`No symbol found at ${entryFileAbs}:${line}:${column}`);
185
332
  }
186
- return getTypeInfo(program, node, sourceFile);
333
+ return getHoverInfo(program, node, sourceFile, include_docs);
187
334
  }
188
335
 
189
336
  // src/mcp.ts
@@ -200,8 +347,8 @@ Manual setup:
200
347
  Run: claude mcp add prinfer node /path/to/prinfer-mcp
201
348
 
202
349
  Provided tools:
203
- infer_type(file, name, line?, project?)
204
- Infer the TypeScript type of a function or variable.
350
+ hover(file, line, column, include_docs?, project?)
351
+ Get TypeScript type information at a specific position.
205
352
 
206
353
  See also:
207
354
  prinfer --help CLI for direct type inspection
@@ -212,28 +359,37 @@ if (process.argv.includes("--help") || process.argv.includes("-h")) {
212
359
  }
213
360
  var server = new import_mcp.McpServer({
214
361
  name: "prinfer",
215
- version: "0.2.1"
362
+ version: "0.3.0"
216
363
  });
217
364
  server.tool(
218
- "infer_type",
219
- "Infer the TypeScript type of a function or variable in a file. Returns the type signature and optionally the return type for functions.",
365
+ "hover",
366
+ "Get TypeScript type information at a specific position in a file. Returns the type signature, return type, documentation, and symbol kind.",
220
367
  {
221
368
  file: import_zod.z.string().describe("Path to the TypeScript file"),
222
- name: import_zod.z.string().describe("Name of the function or variable to inspect"),
223
- line: import_zod.z.number().optional().describe("Optional line number to narrow search (1-based)"),
369
+ line: import_zod.z.number().describe("1-based line number"),
370
+ column: import_zod.z.number().describe("1-based column (character position)"),
371
+ include_docs: import_zod.z.boolean().optional().describe("Include JSDoc/TSDoc documentation"),
224
372
  project: import_zod.z.string().optional().describe("Optional path to tsconfig.json")
225
373
  },
226
- async ({ file, name, line, project }) => {
374
+ async ({ file, line, column, include_docs, project }) => {
227
375
  try {
228
- const result = inferType(file, name, { line, project });
376
+ const result = hover(file, line, column, { include_docs, project });
229
377
  let text = `Type: ${result.signature}`;
230
378
  if (result.returnType) {
231
379
  text += `
232
380
  Returns: ${result.returnType}`;
233
381
  }
234
- if (result.line) {
382
+ if (result.name) {
383
+ text += `
384
+ Name: ${result.name}`;
385
+ }
386
+ text += `
387
+ Kind: ${result.kind}`;
388
+ text += `
389
+ Position: ${result.line}:${result.column}`;
390
+ if (result.documentation) {
235
391
  text += `
236
- Line: ${result.line}`;
392
+ Documentation: ${result.documentation}`;
237
393
  }
238
394
  return { content: [{ type: "text", text }] };
239
395
  } catch (error) {
package/dist/mcp.cjs.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":";;;;;;;;;;;;;;;;;;;;;;;;;;AACA,iBAA0B;AAC1B,mBAAqC;AACrC,iBAAkB;;;ACHlB,qBAAe;AACf,IAAAA,oBAAiB;;;ACDjB,uBAAiB;AACjB,wBAAe;AAMR,SAAS,oBAAoB,UAAsC;AACzE,SACC,kBAAAC,QAAG,eAAe,UAAU,kBAAAA,QAAG,IAAI,YAAY,eAAe,KAC9D;AAEF;AAKO,SAAS,YACf,cACA,SACa;AACb,QAAM,UAAU,iBAAAC,QAAK,QAAQ,YAAY;AACzC,QAAM,eAAe,UAClB,iBAAAA,QAAK,QAAQ,QAAQ,IAAI,GAAG,OAAO,IACnC,oBAAoB,OAAO;AAE9B,MAAI,CAAC,cAAc;AAElB,WAAO,kBAAAD,QAAG,cAAc,CAAC,YAAY,GAAG;AAAA,MACvC,QAAQ,kBAAAA,QAAG,aAAa;AAAA,MACxB,QAAQ,kBAAAA,QAAG,WAAW;AAAA,MACtB,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,SAAS;AAAA,MACT,kBAAkB,kBAAAA,QAAG,qBAAqB;AAAA,MAC1C,cAAc;AAAA,IACf,CAAC;AAAA,EACF;AAEA,QAAM,MAAM,kBAAAA,QAAG,eAAe,cAAc,kBAAAA,QAAG,IAAI,QAAQ;AAC3D,MAAI,IAAI,OAAO;AACd,UAAM,IAAI;AAAA,MACT,kBAAAA,QAAG,6BAA6B,IAAI,MAAM,aAAa,IAAI;AAAA,IAC5D;AAAA,EACD;AAEA,QAAM,SAAS,kBAAAA,QAAG;AAAA,IACjB,IAAI;AAAA,IACJ,kBAAAA,QAAG;AAAA,IACH,iBAAAC,QAAK,QAAQ,YAAY;AAAA,EAC1B;AACA,SAAO,kBAAAD,QAAG,cAAc;AAAA,IACvB,WAAW,OAAO;AAAA,IAClB,SAAS,OAAO;AAAA,EACjB,CAAC;AACF;AAEA,SAAS,gBACR,GACgD;AAChD,SAAO,CAAC,CAAC,MAAM,kBAAAA,QAAG,gBAAgB,CAAC,KAAK,kBAAAA,QAAG,qBAAqB,CAAC;AAClE;AAEA,SAAS,aACR,GACqB;AACrB,MAAI,CAAC,EAAG,QAAO;AACf,MAAI,kBAAAA,QAAG,aAAa,CAAC,EAAG,QAAO,EAAE;AACjC,MAAI,kBAAAA,QAAG,gBAAgB,CAAC,EAAG,QAAO,EAAE;AACpC,MAAI,kBAAAA,QAAG,iBAAiB,CAAC,EAAG,QAAO,EAAE;AACrC,SAAO;AACR;AAEA,SAAS,oBAAoB,MAAe,MAAuB;AAElE,MAAI,kBAAAA,QAAG,sBAAsB,IAAI,KAAK,KAAK,MAAM,SAAS,KAAM,QAAO;AAGvE,MACC,kBAAAA,QAAG,sBAAsB,IAAI,KAC7B,kBAAAA,QAAG,aAAa,KAAK,IAAI,KACzB,KAAK,KAAK,SAAS,MAClB;AACD,WAAO,gBAAgB,KAAK,WAAW;AAAA,EACxC;AAGA,OACE,kBAAAA,QAAG,oBAAoB,IAAI,KAAK,kBAAAA,QAAG,kBAAkB,IAAI,MAC1D,aAAa,KAAK,IAAI,MAAM,MAC3B;AACD,WAAO;AAAA,EACR;AAIA,MAAI,kBAAAA,QAAG,qBAAqB,IAAI,KAAK,aAAa,KAAK,IAAI,MAAM,MAAM;AACtE,WAAO,gBAAgB,KAAK,WAAW;AAAA,EACxC;AAEA,SAAO;AACR;AAKA,SAAS,gBAAgB,MAAe,MAAuB;AAC9D,MACC,kBAAAA,QAAG,sBAAsB,IAAI,KAC7B,kBAAAA,QAAG,aAAa,KAAK,IAAI,KACzB,KAAK,KAAK,SAAS,MAClB;AACD,WAAO;AAAA,EACR;AACA,SAAO;AACR;AAKA,SAAS,YAAY,MAAe,MAAuB;AAC1D,SAAO,oBAAoB,MAAM,IAAI,KAAK,gBAAgB,MAAM,IAAI;AACrE;AAKO,SAAS,cACf,YACA,MACS;AACT,QAAM,EAAE,KAAK,IAAI,WAAW;AAAA,IAC3B,KAAK,SAAS,UAAU;AAAA,EACzB;AACA,SAAO,OAAO;AACf;AA2BO,SAAS,sBACf,YACA,MACA,MACsB;AACtB,MAAI;AAEJ,QAAM,QAAQ,CAAC,SAAkB;AAChC,QAAI,MAAO;AACX,QAAI,YAAY,MAAM,IAAI,GAAG;AAC5B,UAAI,SAAS,QAAW;AACvB,cAAM,WAAW,cAAc,YAAY,IAAI;AAC/C,YAAI,aAAa,MAAM;AACtB,kBAAQ;AACR;AAAA,QACD;AAAA,MACD,OAAO;AACN,gBAAQ;AACR;AAAA,MACD;AAAA,IACD;AACA,sBAAAE,QAAG,aAAa,MAAM,KAAK;AAAA,EAC5B;AAEA,QAAM,UAAU;AAChB,SAAO;AACR;AAKO,SAAS,YACf,SACA,MACA,YACqB;AACrB,QAAM,UAAU,QAAQ,eAAe;AACvC,QAAM,KAAK,cAAc,KAAK,cAAc;AAC5C,QAAM,OAAO,cAAc,IAAI,IAAI;AAEnC,MAAI;AAGJ,MAAI,kBAAAA,QAAG,sBAAsB,IAAI,KAAK,kBAAAA,QAAG,oBAAoB,IAAI,GAAG;AACnE,UAAM,QAAQ,4BAA4B,IAAI,KAAK;AAAA,EACpD,WAAW,kBAAAA,QAAG,sBAAsB,IAAI,GAAG;AAC1C,UAAM,OAAO,KAAK;AAClB,QAAI,gBAAgB,IAAI;AACvB,YAAM,QAAQ,4BAA4B,IAAI,KAAK;AAAA,EACrD,WAAW,kBAAAA,QAAG,qBAAqB,IAAI,GAAG;AACzC,UAAM,OAAO,KAAK;AAClB,QAAI,gBAAgB,IAAI;AACvB,YAAM,QAAQ,4BAA4B,IAAI,KAAK;AAAA,EACrD,WAAW,kBAAAA,QAAG,kBAAkB,IAAI,GAAG;AAEtC,UAAM,QAAQ,4BAA4B,IAAI,KAAK;AAAA,EACpD;AAEA,QAAM,QAAQ,kBAAAA,QAAG,gBAAgB;AAEjC,MAAI,KAAK;AACR,UAAM,YAAY,QAAQ,kBAAkB,KAAK,QAAW,KAAK;AACjE,UAAM,MAAM,QAAQ,yBAAyB,GAAG;AAChD,UAAM,aAAa,QAAQ,aAAa,KAAK,QAAW,KAAK;AAC7D,WAAO,EAAE,WAAW,YAAY,KAAK;AAAA,EACtC;AAGA,QAAM,eAAe;AACrB,MAAI,WAAoB;AACxB,MAAI,aAAa,QAAQ,kBAAAA,QAAG,aAAa,aAAa,IAAI,GAAG;AAC5D,eAAW,aAAa;AAAA,EACzB;AAEA,QAAM,IAAI,QAAQ,kBAAkB,QAAQ;AAC5C,SAAO,EAAE,WAAW,QAAQ,aAAa,GAAG,QAAW,KAAK,GAAG,KAAK;AACrE;;;ADpMO,SAAS,UACf,MACA,MACA,SACqB;AAErB,QAAM,OACL,OAAO,YAAY,WAAW,EAAE,SAAS,QAAQ,IAAK,WAAW,CAAC;AACnE,QAAM,EAAE,MAAM,QAAQ,IAAI;AAE1B,QAAM,eAAe,kBAAAC,QAAK,QAAQ,QAAQ,IAAI,GAAG,IAAI;AAErD,MAAI,CAAC,eAAAC,QAAG,WAAW,YAAY,GAAG;AACjC,UAAM,IAAI,MAAM,mBAAmB,YAAY,EAAE;AAAA,EAClD;AAEA,QAAM,UAAU,YAAY,cAAc,OAAO;AACjD,QAAM,aAAa,QAAQ,cAAc,YAAY;AAErD,MAAI,CAAC,YAAY;AAChB,UAAM,IAAI;AAAA,MACT,iFAAiF,YAAY;AAAA,IAC9F;AAAA,EACD;AAEA,QAAM,OAAO,sBAAsB,YAAY,MAAM,IAAI;AACzD,MAAI,CAAC,MAAM;AACV,UAAM,WAAW,SAAS,SAAY,YAAY,IAAI,KAAK;AAC3D,UAAM,IAAI;AAAA,MACT,oBAAoB,IAAI,IAAI,QAAQ,aAAa,YAAY;AAAA,IAC9D;AAAA,EACD;AAEA,SAAO,YAAY,SAAS,MAAM,UAAU;AAC7C;;;ADtEA,IAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBX,KAAK;AAEP,IAAI,QAAQ,KAAK,SAAS,QAAQ,KAAK,QAAQ,KAAK,SAAS,IAAI,GAAG;AACnE,UAAQ,IAAI,IAAI;AAChB,UAAQ,KAAK,CAAC;AACf;AAEA,IAAM,SAAS,IAAI,qBAAU;AAAA,EAC5B,MAAM;AAAA,EACN,SAAS;AACV,CAAC;AAED,OAAO;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,IACC,MAAM,aAAE,OAAO,EAAE,SAAS,6BAA6B;AAAA,IACvD,MAAM,aACJ,OAAO,EACP,SAAS,6CAA6C;AAAA,IACxD,MAAM,aACJ,OAAO,EACP,SAAS,EACT,SAAS,iDAAiD;AAAA,IAC5D,SAAS,aACP,OAAO,EACP,SAAS,EACT,SAAS,gCAAgC;AAAA,EAC5C;AAAA,EACA,OAAO,EAAE,MAAM,MAAM,MAAM,QAAQ,MAAM;AACxC,QAAI;AACH,YAAM,SAAS,UAAU,MAAM,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtD,UAAI,OAAO,SAAS,OAAO,SAAS;AACpC,UAAI,OAAO,YAAY;AACtB,gBAAQ;AAAA,WAAc,OAAO,UAAU;AAAA,MACxC;AACA,UAAI,OAAO,MAAM;AAChB,gBAAQ;AAAA,QAAW,OAAO,IAAI;AAAA,MAC/B;AACA,aAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC,EAAE;AAAA,IAC5C,SAAS,OAAO;AACf,aAAO;AAAA,QACN,SAAS;AAAA,UACR;AAAA,YACC,MAAM;AAAA,YACN,MAAM,UAAW,MAAgB,OAAO;AAAA,UACzC;AAAA,QACD;AAAA,QACA,SAAS;AAAA,MACV;AAAA,IACD;AAAA,EACD;AACD;AAEA,eAAe,OAAO;AACrB,QAAM,YAAY,IAAI,kCAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAC/B;AAEA,KAAK,EAAE,MAAM,QAAQ,KAAK;","names":["import_node_path","ts","path","ts","path","fs"]}
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":["import_node_path","ts","path","ts","nodeWithName","sig","t","path","fs"]}