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/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/index.ts","../src/core.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { inferType } from \"./index.js\";\n\nconst HELP = `\nprinfer - TypeScript type inference inspection tool\n\nUsage:\n prinfer <file.ts>[:<line>] <name> [--project <tsconfig.json>]\n prinfer setup\n\nCommands:\n setup Install MCP server and skill for Claude Code\n\nArguments:\n file.ts Path to the TypeScript file\n :line Optional line number to narrow search (e.g., file.ts:75)\n name Name of the function/variable to inspect\n\nOptions:\n --project, -p Path to tsconfig.json (optional)\n --help, -h Show this help message\n\nExamples:\n prinfer src/utils.ts myFunction\n prinfer src/utils.ts:75 commandResult\n prinfer setup\n`.trim();\n\nconst MANUAL_SETUP = `\nManual setup instructions:\n\n1. Add MCP server:\n Run: claude mcp add prinfer node /path/to/prinfer-mcp\n\n2. Create skill file at ~/.claude/skills/prefer-infer.md:\n See https://github.com/clockblocker/prinfer for skill content.\n`.trim();\n\nfunction getMcpBinaryPath(): string {\n\t// Resolve absolute path to prinfer-mcp\n\t// It's in the same directory as this script (dist/)\n\tconst thisScript = new URL(import.meta.url).pathname;\n\treturn path.join(path.dirname(thisScript), \"mcp.js\");\n}\n\nfunction installMcpServer(): boolean {\n\ttry {\n\t\tconst mcpPath = getMcpBinaryPath();\n\n\t\t// Always remove first to ensure correct path (handles upgrades/fixes)\n\t\ttry {\n\t\t\texecSync(\"claude mcp remove prinfer\", { stdio: \"pipe\" });\n\t\t} catch {\n\t\t\t// Ignore if not exists\n\t\t}\n\n\t\t// Add MCP server with absolute path\n\t\texecSync(`claude mcp add prinfer node ${mcpPath}`, {\n\t\t\tstdio: \"inherit\",\n\t\t});\n\t\tconsole.log(\"[ok] Added prinfer MCP server\");\n\t\treturn true;\n\t} catch (err) {\n\t\tconsole.error(`[error] MCP setup failed: ${(err as Error).message}`);\n\t\treturn false;\n\t}\n}\n\nconst SKILL_CONTENT = `# TypeScript Type Inference (prinfer)\n\n## Coding Guideline\n\nWhen writing TypeScript code, prefer relying on type inference over explicit type annotations:\n\n- Let TypeScript infer return types for functions when the implementation makes them obvious\n- Let TypeScript infer variable types from their initializers\n- Only add explicit types when:\n - The inferred type is too wide (e.g., \\`string\\` instead of a literal type)\n - The type serves as documentation for complex structures\n - You're defining a public API contract\n\nUse the \\`prinfer\\` MCP tool (\\`infer_type\\`) to verify what TypeScript infers before adding explicit types.\n\n## Commands\n\n### /check-type\n\nCheck the inferred type of a TypeScript symbol.\n\nUsage: \\`/check-type <file>:<line> <name>\\` or \\`/check-type <file> <name>\\`\n\nExamples:\n- \\`/check-type src/utils.ts:75 commandResult\\`\n- \\`/check-type src/utils.ts myFunction\\`\n\n<command-name>check-type</command-name>\n\nUse the \\`infer_type\\` MCP tool to check the type:\n1. Parse the arguments to extract file, optional line number, and symbol name\n2. Call \\`infer_type(file, name, line?)\\`\n3. Report the inferred signature and return type\n`;\n\nfunction runSetup(): void {\n\tconst homeDir = os.homedir();\n\tconst claudeDir = path.join(homeDir, \".claude\");\n\n\tif (!fs.existsSync(claudeDir)) {\n\t\tconsole.error(\"Error: ~/.claude directory not found.\");\n\t\tconsole.error(\"Make sure Claude Code is installed first.\\n\");\n\t\tconsole.error(MANUAL_SETUP);\n\t\tprocess.exit(1);\n\t}\n\n\t// Install MCP server using claude CLI\n\tconst mcpOk = installMcpServer();\n\n\t// Install skill\n\tlet skillOk = false;\n\tconst skillsDir = path.join(claudeDir, \"skills\");\n\tconst skillFile = path.join(skillsDir, \"prefer-infer.md\");\n\ttry {\n\t\tif (!fs.existsSync(skillsDir)) {\n\t\t\tfs.mkdirSync(skillsDir, { recursive: true });\n\t\t}\n\n\t\tif (fs.existsSync(skillFile)) {\n\t\t\tconsole.log(\"[ok] Skill already installed\");\n\t\t\tskillOk = true;\n\t\t} else {\n\t\t\tfs.writeFileSync(skillFile, SKILL_CONTENT);\n\t\t\tconsole.log(\n\t\t\t\t\"[ok] Installed skill to ~/.claude/skills/prefer-infer.md\",\n\t\t\t);\n\t\t\tskillOk = true;\n\t\t}\n\t} catch (err) {\n\t\tconsole.error(\n\t\t\t`[error] Failed to install skill: ${(err as Error).message}`,\n\t\t);\n\t}\n\n\tif (mcpOk && skillOk) {\n\t\tconsole.log(\"\\nSetup complete! Restart Claude Code to use prinfer.\");\n\t} else {\n\t\tconsole.error(\"\\nSome steps failed. Manual setup:\\n\");\n\t\tconsole.error(MANUAL_SETUP);\n\t\tprocess.exit(1);\n\t}\n}\n\ninterface CliOptions {\n\tfile: string;\n\tname: string;\n\tline?: number;\n\tproject?: string;\n}\n\nfunction parseFileArg(arg: string): { file: string; line?: number } {\n\t// Match pattern: file.ts:123 or just file.ts\n\tconst match = arg.match(/^(.+):(\\d+)$/);\n\tif (match) {\n\t\treturn { file: match[1], line: Number.parseInt(match[2], 10) };\n\t}\n\treturn { file: arg };\n}\n\nfunction parseArgs(argv: string[]): CliOptions | null {\n\tconst args = argv.slice(2);\n\n\t// Check for help flag\n\tif (args.includes(\"--help\") || args.includes(\"-h\") || args.length === 0) {\n\t\tconsole.log(HELP);\n\t\treturn null;\n\t}\n\n\t// Check for setup command\n\tif (args[0] === \"setup\") {\n\t\trunSetup();\n\t\treturn null;\n\t}\n\n\tconst fileArg = args[0];\n\tconst name = args[1];\n\n\tif (!fileArg || !name) {\n\t\tconsole.error(\n\t\t\t\"Error: Both <file> and <name> arguments are required.\\n\",\n\t\t);\n\t\tconsole.log(HELP);\n\t\tprocess.exit(1);\n\t}\n\n\tconst { file, line } = parseFileArg(fileArg);\n\n\t// Find project option\n\tlet project: string | undefined;\n\tconst projectIdx = args.findIndex((a) => a === \"--project\" || a === \"-p\");\n\tif (projectIdx >= 0) {\n\t\tproject = args[projectIdx + 1];\n\t\tif (!project) {\n\t\t\tconsole.error(\"Error: --project requires a path argument.\\n\");\n\t\t\tconsole.log(HELP);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\treturn { file, name, line, project };\n}\n\nfunction main(): void {\n\tconst options = parseArgs(process.argv);\n\n\tif (!options) {\n\t\tprocess.exit(0);\n\t}\n\n\ttry {\n\t\tconst result = inferType(options.file, options.name, {\n\t\t\tline: options.line,\n\t\t\tproject: options.project,\n\t\t});\n\n\t\tconsole.log(result.signature);\n\t\tif (result.returnType) {\n\t\t\tconsole.log(\"returns:\", result.returnType);\n\t\t}\n\t} catch (error) {\n\t\tconsole.error((error as Error).message);\n\t\tprocess.exit(1);\n\t}\n}\n\nmain();\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,gCAAyB;AACzB,IAAAA,kBAAe;AACf,qBAAe;AACf,IAAAC,oBAAiB;;;ACJjB,qBAAe;AACf,IAAAC,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;;;AD5EA;AAOA,IAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBX,KAAK;AAEP,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQnB,KAAK;AAEP,SAAS,mBAA2B;AAGnC,QAAM,aAAa,IAAI,IAAI,YAAY,GAAG,EAAE;AAC5C,SAAO,kBAAAC,QAAK,KAAK,kBAAAA,QAAK,QAAQ,UAAU,GAAG,QAAQ;AACpD;AAEA,SAAS,mBAA4B;AACpC,MAAI;AACH,UAAM,UAAU,iBAAiB;AAGjC,QAAI;AACH,8CAAS,6BAA6B,EAAE,OAAO,OAAO,CAAC;AAAA,IACxD,QAAQ;AAAA,IAER;AAGA,4CAAS,+BAA+B,OAAO,IAAI;AAAA,MAClD,OAAO;AAAA,IACR,CAAC;AACD,YAAQ,IAAI,+BAA+B;AAC3C,WAAO;AAAA,EACR,SAAS,KAAK;AACb,YAAQ,MAAM,6BAA8B,IAAc,OAAO,EAAE;AACnE,WAAO;AAAA,EACR;AACD;AAEA,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCtB,SAAS,WAAiB;AACzB,QAAM,UAAU,eAAAC,QAAG,QAAQ;AAC3B,QAAM,YAAY,kBAAAD,QAAK,KAAK,SAAS,SAAS;AAE9C,MAAI,CAAC,gBAAAE,QAAG,WAAW,SAAS,GAAG;AAC9B,YAAQ,MAAM,uCAAuC;AACrD,YAAQ,MAAM,6CAA6C;AAC3D,YAAQ,MAAM,YAAY;AAC1B,YAAQ,KAAK,CAAC;AAAA,EACf;AAGA,QAAM,QAAQ,iBAAiB;AAG/B,MAAI,UAAU;AACd,QAAM,YAAY,kBAAAF,QAAK,KAAK,WAAW,QAAQ;AAC/C,QAAM,YAAY,kBAAAA,QAAK,KAAK,WAAW,iBAAiB;AACxD,MAAI;AACH,QAAI,CAAC,gBAAAE,QAAG,WAAW,SAAS,GAAG;AAC9B,sBAAAA,QAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IAC5C;AAEA,QAAI,gBAAAA,QAAG,WAAW,SAAS,GAAG;AAC7B,cAAQ,IAAI,8BAA8B;AAC1C,gBAAU;AAAA,IACX,OAAO;AACN,sBAAAA,QAAG,cAAc,WAAW,aAAa;AACzC,cAAQ;AAAA,QACP;AAAA,MACD;AACA,gBAAU;AAAA,IACX;AAAA,EACD,SAAS,KAAK;AACb,YAAQ;AAAA,MACP,oCAAqC,IAAc,OAAO;AAAA,IAC3D;AAAA,EACD;AAEA,MAAI,SAAS,SAAS;AACrB,YAAQ,IAAI,uDAAuD;AAAA,EACpE,OAAO;AACN,YAAQ,MAAM,sCAAsC;AACpD,YAAQ,MAAM,YAAY;AAC1B,YAAQ,KAAK,CAAC;AAAA,EACf;AACD;AASA,SAAS,aAAa,KAA8C;AAEnE,QAAM,QAAQ,IAAI,MAAM,cAAc;AACtC,MAAI,OAAO;AACV,WAAO,EAAE,MAAM,MAAM,CAAC,GAAG,MAAM,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,EAAE;AAAA,EAC9D;AACA,SAAO,EAAE,MAAM,IAAI;AACpB;AAEA,SAAS,UAAU,MAAmC;AACrD,QAAM,OAAO,KAAK,MAAM,CAAC;AAGzB,MAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,WAAW,GAAG;AACxE,YAAQ,IAAI,IAAI;AAChB,WAAO;AAAA,EACR;AAGA,MAAI,KAAK,CAAC,MAAM,SAAS;AACxB,aAAS;AACT,WAAO;AAAA,EACR;AAEA,QAAM,UAAU,KAAK,CAAC;AACtB,QAAM,OAAO,KAAK,CAAC;AAEnB,MAAI,CAAC,WAAW,CAAC,MAAM;AACtB,YAAQ;AAAA,MACP;AAAA,IACD;AACA,YAAQ,IAAI,IAAI;AAChB,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,QAAM,EAAE,MAAM,KAAK,IAAI,aAAa,OAAO;AAG3C,MAAI;AACJ,QAAM,aAAa,KAAK,UAAU,CAAC,MAAM,MAAM,eAAe,MAAM,IAAI;AACxE,MAAI,cAAc,GAAG;AACpB,cAAU,KAAK,aAAa,CAAC;AAC7B,QAAI,CAAC,SAAS;AACb,cAAQ,MAAM,8CAA8C;AAC5D,cAAQ,IAAI,IAAI;AAChB,cAAQ,KAAK,CAAC;AAAA,IACf;AAAA,EACD;AAEA,SAAO,EAAE,MAAM,MAAM,MAAM,QAAQ;AACpC;AAEA,SAAS,OAAa;AACrB,QAAM,UAAU,UAAU,QAAQ,IAAI;AAEtC,MAAI,CAAC,SAAS;AACb,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,MAAI;AACH,UAAM,SAAS,UAAU,QAAQ,MAAM,QAAQ,MAAM;AAAA,MACpD,MAAM,QAAQ;AAAA,MACd,SAAS,QAAQ;AAAA,IAClB,CAAC;AAED,YAAQ,IAAI,OAAO,SAAS;AAC5B,QAAI,OAAO,YAAY;AACtB,cAAQ,IAAI,YAAY,OAAO,UAAU;AAAA,IAC1C;AAAA,EACD,SAAS,OAAO;AACf,YAAQ,MAAO,MAAgB,OAAO;AACtC,YAAQ,KAAK,CAAC;AAAA,EACf;AACD;AAEA,KAAK;","names":["import_node_fs","import_node_path","import_node_path","ts","path","ts","path","fs","path","os","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/index.ts","../src/core.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { hover } from \"./index.js\";\n\nconst HELP = `\nprinfer - TypeScript type inference inspection tool\n\nUsage:\n prinfer <file.ts>:<line>:<column> [--docs] [--project <tsconfig.json>]\n prinfer setup\n\nCommands:\n setup Install MCP server and skill for Claude Code\n\nArguments:\n file.ts:line:column Path to TypeScript file with 1-based line and column\n\nOptions:\n --docs, -d Include JSDoc/TSDoc documentation\n --project, -p Path to tsconfig.json (optional)\n --help, -h Show this help message\n\nExamples:\n prinfer src/utils.ts:75:10\n prinfer src/utils.ts:75:10 --docs\n prinfer src/utils.ts:75:10 --project ./tsconfig.json\n prinfer setup\n`.trim();\n\nconst MANUAL_SETUP = `\nManual setup instructions:\n\n1. Add MCP server:\n Run: claude mcp add prinfer node /path/to/prinfer-mcp\n\n2. Create skill file at ~/.claude/skills/prefer-infer.md:\n See https://github.com/clockblocker/prinfer for skill content.\n`.trim();\n\nfunction getMcpBinaryPath(): string {\n\t// Resolve absolute path to prinfer-mcp\n\t// It's in the same directory as this script (dist/)\n\tconst thisScript = new URL(import.meta.url).pathname;\n\treturn path.join(path.dirname(thisScript), \"mcp.js\");\n}\n\nfunction installMcpServer(): boolean {\n\ttry {\n\t\tconst mcpPath = getMcpBinaryPath();\n\n\t\t// Always remove first to ensure correct path (handles upgrades/fixes)\n\t\ttry {\n\t\t\texecSync(\"claude mcp remove prinfer\", { stdio: \"pipe\" });\n\t\t} catch {\n\t\t\t// Ignore if not exists\n\t\t}\n\n\t\t// Add MCP server with absolute path\n\t\texecSync(`claude mcp add prinfer node ${mcpPath}`, {\n\t\t\tstdio: \"inherit\",\n\t\t});\n\t\tconsole.log(\"[ok] Added prinfer MCP server\");\n\t\treturn true;\n\t} catch (err) {\n\t\tconsole.error(`[error] MCP setup failed: ${(err as Error).message}`);\n\t\treturn false;\n\t}\n}\n\nconst SKILL_CONTENT = `# TypeScript Type Inference (prinfer)\n\n## Coding Guideline\n\nWhen writing TypeScript code, prefer relying on type inference over explicit type annotations:\n\n- Let TypeScript infer return types for functions when the implementation makes them obvious\n- Let TypeScript infer variable types from their initializers\n- Only add explicit types when:\n - The inferred type is too wide (e.g., \\`string\\` instead of a literal type)\n - The type serves as documentation for complex structures\n - You're defining a public API contract\n\nUse the \\`prinfer\\` MCP tool (\\`hover\\`) to verify what TypeScript infers before adding explicit types.\n\n## Commands\n\n### /hover\n\nCheck the inferred type at a specific position in a TypeScript file.\n\nUsage: \\`/hover <file>:<line>:<column>\\`\n\nExamples:\n- \\`/hover src/utils.ts:75:10\\`\n- \\`/hover src/utils.ts:42:5\\`\n\n<command-name>hover</command-name>\n\nUse the \\`hover\\` MCP tool to check the type:\n1. Parse the arguments to extract file, line, and column\n2. Call \\`hover(file, line, column, { include_docs: true })\\`\n3. Report the inferred signature, return type, and documentation\n`;\n\nfunction runSetup(): void {\n\tconst homeDir = os.homedir();\n\tconst claudeDir = path.join(homeDir, \".claude\");\n\n\tif (!fs.existsSync(claudeDir)) {\n\t\tconsole.error(\"Error: ~/.claude directory not found.\");\n\t\tconsole.error(\"Make sure Claude Code is installed first.\\n\");\n\t\tconsole.error(MANUAL_SETUP);\n\t\tprocess.exit(1);\n\t}\n\n\t// Install MCP server using claude CLI\n\tconst mcpOk = installMcpServer();\n\n\t// Install skill\n\tlet skillOk = false;\n\tconst skillsDir = path.join(claudeDir, \"skills\");\n\tconst skillFile = path.join(skillsDir, \"prefer-infer.md\");\n\ttry {\n\t\tif (!fs.existsSync(skillsDir)) {\n\t\t\tfs.mkdirSync(skillsDir, { recursive: true });\n\t\t}\n\n\t\tif (fs.existsSync(skillFile)) {\n\t\t\tconsole.log(\"[ok] Skill already installed\");\n\t\t\tskillOk = true;\n\t\t} else {\n\t\t\tfs.writeFileSync(skillFile, SKILL_CONTENT);\n\t\t\tconsole.log(\n\t\t\t\t\"[ok] Installed skill to ~/.claude/skills/prefer-infer.md\",\n\t\t\t);\n\t\t\tskillOk = true;\n\t\t}\n\t} catch (err) {\n\t\tconsole.error(\n\t\t\t`[error] Failed to install skill: ${(err as Error).message}`,\n\t\t);\n\t}\n\n\tif (mcpOk && skillOk) {\n\t\tconsole.log(\"\\nSetup complete! Restart Claude Code to use prinfer.\");\n\t} else {\n\t\tconsole.error(\"\\nSome steps failed. Manual setup:\\n\");\n\t\tconsole.error(MANUAL_SETUP);\n\t\tprocess.exit(1);\n\t}\n}\n\ninterface CliOptions {\n\tfile: string;\n\tline: number;\n\tcolumn: number;\n\tincludeDocs: boolean;\n\tproject?: string;\n}\n\nfunction parsePositionArg(\n\targ: string,\n): { file: string; line: number; column: number } | null {\n\t// Match pattern: file.ts:line:column\n\tconst match = arg.match(/^(.+):(\\d+):(\\d+)$/);\n\tif (match) {\n\t\treturn {\n\t\t\tfile: match[1],\n\t\t\tline: Number.parseInt(match[2], 10),\n\t\t\tcolumn: Number.parseInt(match[3], 10),\n\t\t};\n\t}\n\treturn null;\n}\n\nfunction parseArgs(argv: string[]): CliOptions | null {\n\tconst args = argv.slice(2);\n\n\t// Check for help flag\n\tif (args.includes(\"--help\") || args.includes(\"-h\") || args.length === 0) {\n\t\tconsole.log(HELP);\n\t\treturn null;\n\t}\n\n\t// Check for setup command\n\tif (args[0] === \"setup\") {\n\t\trunSetup();\n\t\treturn null;\n\t}\n\n\tconst positionArg = args[0];\n\tconst parsed = parsePositionArg(positionArg);\n\n\tif (!parsed) {\n\t\tconsole.error(\n\t\t\t\"Error: Position argument must be in format <file>:<line>:<column>\\n\",\n\t\t);\n\t\tconsole.log(HELP);\n\t\tprocess.exit(1);\n\t}\n\n\tconst { file, line, column } = parsed;\n\n\t// Check for docs flag\n\tconst includeDocs = args.includes(\"--docs\") || args.includes(\"-d\");\n\n\t// Find project option\n\tlet project: string | undefined;\n\tconst projectIdx = args.findIndex((a) => a === \"--project\" || a === \"-p\");\n\tif (projectIdx >= 0) {\n\t\tproject = args[projectIdx + 1];\n\t\tif (!project) {\n\t\t\tconsole.error(\"Error: --project requires a path argument.\\n\");\n\t\t\tconsole.log(HELP);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\treturn { file, line, column, includeDocs, project };\n}\n\nfunction main(): void {\n\tconst options = parseArgs(process.argv);\n\n\tif (!options) {\n\t\tprocess.exit(0);\n\t}\n\n\ttry {\n\t\tconst result = hover(options.file, options.line, options.column, {\n\t\t\tinclude_docs: options.includeDocs,\n\t\t\tproject: options.project,\n\t\t});\n\n\t\tconsole.log(result.signature);\n\t\tif (result.returnType) {\n\t\t\tconsole.log(\"returns:\", result.returnType);\n\t\t}\n\t\tif (result.name) {\n\t\t\tconsole.log(\"name:\", result.name);\n\t\t}\n\t\tconsole.log(\"kind:\", result.kind);\n\t\tif (result.documentation) {\n\t\t\tconsole.log(\"docs:\", result.documentation);\n\t\t}\n\t} catch (error) {\n\t\tconsole.error((error as Error).message);\n\t\tprocess.exit(1);\n\t}\n}\n\nmain();\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_fs","import_node_path","import_node_path","ts","path","ts","nodeWithName","sig","t","path","fs","path","os","fs"]}
|
package/dist/cli.js
CHANGED
|
@@ -49,66 +49,203 @@ function loadProgram(entryFileAbs, project) {
|
|
|
49
49
|
function isArrowOrFnExpr(n) {
|
|
50
50
|
return !!n && (ts.isArrowFunction(n) || ts.isFunctionExpression(n));
|
|
51
51
|
}
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if ((ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) && nodeNameText(node.name) === name) {
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
if (ts.isPropertyAssignment(node) && nodeNameText(node.name) === name) {
|
|
68
|
-
return isArrowOrFnExpr(node.initializer);
|
|
52
|
+
function findSmallestNodeAtPosition(sourceFile, position) {
|
|
53
|
+
let result;
|
|
54
|
+
function visit(node) {
|
|
55
|
+
const start = node.getStart(sourceFile);
|
|
56
|
+
const end = node.getEnd();
|
|
57
|
+
if (position < start || position >= end) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (!result || node.getWidth(sourceFile) <= result.getWidth(sourceFile)) {
|
|
61
|
+
result = node;
|
|
62
|
+
}
|
|
63
|
+
ts.forEachChild(node, visit);
|
|
69
64
|
}
|
|
70
|
-
|
|
65
|
+
visit(sourceFile);
|
|
66
|
+
return result;
|
|
71
67
|
}
|
|
72
|
-
function
|
|
73
|
-
|
|
68
|
+
function findHoverableAncestor(sourceFile, position) {
|
|
69
|
+
const smallestNode = findSmallestNodeAtPosition(sourceFile, position);
|
|
70
|
+
if (!smallestNode) return void 0;
|
|
71
|
+
let bestMatch = smallestNode;
|
|
72
|
+
function visit(n) {
|
|
73
|
+
const start = n.getStart(sourceFile);
|
|
74
|
+
const end = n.getEnd();
|
|
75
|
+
if (position < start || position >= end) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (ts.isCallExpression(n)) {
|
|
79
|
+
const expr = n.expression;
|
|
80
|
+
if (ts.isIdentifier(expr)) {
|
|
81
|
+
if (position >= expr.getStart(sourceFile) && position < expr.getEnd()) {
|
|
82
|
+
bestMatch = n;
|
|
83
|
+
}
|
|
84
|
+
} else if (ts.isPropertyAccessExpression(expr)) {
|
|
85
|
+
if (position >= expr.name.getStart(sourceFile) && position < expr.name.getEnd()) {
|
|
86
|
+
bestMatch = n;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (ts.isFunctionDeclaration(n) && n.name) {
|
|
91
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
92
|
+
bestMatch = n;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (ts.isVariableDeclaration(n) && ts.isIdentifier(n.name)) {
|
|
96
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
97
|
+
bestMatch = n;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if ((ts.isMethodDeclaration(n) || ts.isMethodSignature(n)) && ts.isIdentifier(n.name)) {
|
|
101
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
102
|
+
bestMatch = n;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (ts.isClassDeclaration(n) && n.name) {
|
|
106
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
107
|
+
bestMatch = n;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (ts.isInterfaceDeclaration(n) && n.name) {
|
|
111
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
112
|
+
bestMatch = n;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
ts.forEachChild(n, visit);
|
|
74
116
|
return true;
|
|
75
117
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
function isNamedNode(node, name) {
|
|
79
|
-
return isFunctionLikeNamed(node, name) || isVariableNamed(node, name);
|
|
118
|
+
visit(sourceFile);
|
|
119
|
+
return bestMatch;
|
|
80
120
|
}
|
|
81
|
-
function
|
|
82
|
-
const
|
|
83
|
-
|
|
121
|
+
function findNodeAtPosition(sourceFile, line, column) {
|
|
122
|
+
const lineCount = sourceFile.getLineStarts().length;
|
|
123
|
+
if (line < 1 || line > lineCount) {
|
|
124
|
+
return void 0;
|
|
125
|
+
}
|
|
126
|
+
const lineStart = sourceFile.getLineStarts()[line - 1];
|
|
127
|
+
const lineEnd = line < lineCount ? sourceFile.getLineStarts()[line] : sourceFile.getEnd();
|
|
128
|
+
const lineLength = lineEnd - lineStart;
|
|
129
|
+
if (column < 1 || column > lineLength + 1) {
|
|
130
|
+
return void 0;
|
|
131
|
+
}
|
|
132
|
+
const position = sourceFile.getPositionOfLineAndCharacter(
|
|
133
|
+
line - 1,
|
|
134
|
+
column - 1
|
|
84
135
|
);
|
|
85
|
-
return
|
|
136
|
+
return findHoverableAncestor(sourceFile, position);
|
|
86
137
|
}
|
|
87
|
-
function
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
} else {
|
|
99
|
-
found = node;
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
138
|
+
function getSymbolKind(node) {
|
|
139
|
+
if (ts.isFunctionDeclaration(node)) return "function";
|
|
140
|
+
if (ts.isArrowFunction(node)) return "function";
|
|
141
|
+
if (ts.isFunctionExpression(node)) return "function";
|
|
142
|
+
if (ts.isMethodDeclaration(node)) return "method";
|
|
143
|
+
if (ts.isMethodSignature(node)) return "method";
|
|
144
|
+
if (ts.isVariableDeclaration(node)) {
|
|
145
|
+
const init = node.initializer;
|
|
146
|
+
if (init && (ts.isArrowFunction(init) || ts.isFunctionExpression(init))) {
|
|
147
|
+
return "function";
|
|
102
148
|
}
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return
|
|
149
|
+
return "variable";
|
|
150
|
+
}
|
|
151
|
+
if (ts.isParameter(node)) return "parameter";
|
|
152
|
+
if (ts.isPropertyDeclaration(node)) return "property";
|
|
153
|
+
if (ts.isPropertySignature(node)) return "property";
|
|
154
|
+
if (ts.isPropertyAccessExpression(node)) return "property";
|
|
155
|
+
if (ts.isCallExpression(node)) return "call";
|
|
156
|
+
if (ts.isTypeAliasDeclaration(node)) return "type";
|
|
157
|
+
if (ts.isInterfaceDeclaration(node)) return "interface";
|
|
158
|
+
if (ts.isClassDeclaration(node)) return "class";
|
|
159
|
+
if (ts.isIdentifier(node)) return "identifier";
|
|
160
|
+
return "unknown";
|
|
161
|
+
}
|
|
162
|
+
function getNodeName(node) {
|
|
163
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
164
|
+
return node.name.text;
|
|
165
|
+
}
|
|
166
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
167
|
+
return node.name.text;
|
|
168
|
+
}
|
|
169
|
+
if ((ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) && ts.isIdentifier(node.name)) {
|
|
170
|
+
return node.name.text;
|
|
171
|
+
}
|
|
172
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
173
|
+
return node.name.text;
|
|
174
|
+
}
|
|
175
|
+
if (ts.isCallExpression(node)) {
|
|
176
|
+
const expr = node.expression;
|
|
177
|
+
if (ts.isIdentifier(expr)) return expr.text;
|
|
178
|
+
if (ts.isPropertyAccessExpression(expr)) return expr.name.text;
|
|
179
|
+
}
|
|
180
|
+
if (ts.isParameter(node) && ts.isIdentifier(node.name)) {
|
|
181
|
+
return node.name.text;
|
|
182
|
+
}
|
|
183
|
+
if (ts.isIdentifier(node)) {
|
|
184
|
+
return node.text;
|
|
185
|
+
}
|
|
186
|
+
if (ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isClassDeclaration(node)) {
|
|
187
|
+
return node.name?.text;
|
|
188
|
+
}
|
|
189
|
+
return void 0;
|
|
107
190
|
}
|
|
108
|
-
function
|
|
191
|
+
function getDocumentation(checker, symbol) {
|
|
192
|
+
if (!symbol) return void 0;
|
|
193
|
+
const docs = symbol.getDocumentationComment(checker);
|
|
194
|
+
if (docs.length === 0) return void 0;
|
|
195
|
+
return ts.displayPartsToString(docs);
|
|
196
|
+
}
|
|
197
|
+
function getHoverInfo(program, node, sourceFile, includeDocs) {
|
|
109
198
|
const checker = program.getTypeChecker();
|
|
110
|
-
const sf = sourceFile
|
|
111
|
-
const line =
|
|
199
|
+
const sf = sourceFile;
|
|
200
|
+
const { line, character } = sf.getLineAndCharacterOfPosition(
|
|
201
|
+
node.getStart(sf)
|
|
202
|
+
);
|
|
203
|
+
const flags = ts.TypeFormatFlags.NoTruncation;
|
|
204
|
+
const kind = getSymbolKind(node);
|
|
205
|
+
const name = getNodeName(node);
|
|
206
|
+
let symbol;
|
|
207
|
+
if (ts.isCallExpression(node)) {
|
|
208
|
+
const expr = node.expression;
|
|
209
|
+
if (ts.isPropertyAccessExpression(expr)) {
|
|
210
|
+
symbol = checker.getSymbolAtLocation(expr.name);
|
|
211
|
+
} else {
|
|
212
|
+
symbol = checker.getSymbolAtLocation(expr);
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
const nodeWithName2 = node;
|
|
216
|
+
if (nodeWithName2.name) {
|
|
217
|
+
symbol = checker.getSymbolAtLocation(nodeWithName2.name);
|
|
218
|
+
} else {
|
|
219
|
+
symbol = checker.getSymbolAtLocation(node);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const documentation = includeDocs ? getDocumentation(checker, symbol) : void 0;
|
|
223
|
+
if (ts.isCallExpression(node)) {
|
|
224
|
+
const sig2 = checker.getResolvedSignature(node);
|
|
225
|
+
if (sig2) {
|
|
226
|
+
const signature = checker.signatureToString(sig2, void 0, flags);
|
|
227
|
+
const ret = checker.getReturnTypeOfSignature(sig2);
|
|
228
|
+
const returnType = checker.typeToString(ret, void 0, flags);
|
|
229
|
+
return {
|
|
230
|
+
signature,
|
|
231
|
+
returnType,
|
|
232
|
+
line: line + 1,
|
|
233
|
+
column: character + 1,
|
|
234
|
+
documentation,
|
|
235
|
+
kind,
|
|
236
|
+
name
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
const t2 = checker.getTypeAtLocation(node);
|
|
240
|
+
return {
|
|
241
|
+
signature: checker.typeToString(t2, void 0, flags),
|
|
242
|
+
line: line + 1,
|
|
243
|
+
column: character + 1,
|
|
244
|
+
documentation,
|
|
245
|
+
kind,
|
|
246
|
+
name
|
|
247
|
+
};
|
|
248
|
+
}
|
|
112
249
|
let sig;
|
|
113
250
|
if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
|
|
114
251
|
sig = checker.getSignatureFromDeclaration(node) ?? void 0;
|
|
@@ -123,26 +260,39 @@ function getTypeInfo(program, node, sourceFile) {
|
|
|
123
260
|
} else if (ts.isMethodSignature(node)) {
|
|
124
261
|
sig = checker.getSignatureFromDeclaration(node) ?? void 0;
|
|
125
262
|
}
|
|
126
|
-
const flags = ts.TypeFormatFlags.NoTruncation;
|
|
127
263
|
if (sig) {
|
|
128
264
|
const signature = checker.signatureToString(sig, void 0, flags);
|
|
129
265
|
const ret = checker.getReturnTypeOfSignature(sig);
|
|
130
266
|
const returnType = checker.typeToString(ret, void 0, flags);
|
|
131
|
-
return {
|
|
267
|
+
return {
|
|
268
|
+
signature,
|
|
269
|
+
returnType,
|
|
270
|
+
line: line + 1,
|
|
271
|
+
column: character + 1,
|
|
272
|
+
documentation,
|
|
273
|
+
kind,
|
|
274
|
+
name
|
|
275
|
+
};
|
|
132
276
|
}
|
|
133
277
|
const nodeWithName = node;
|
|
134
|
-
let
|
|
278
|
+
let targetNode = node;
|
|
135
279
|
if (nodeWithName.name && ts.isIdentifier(nodeWithName.name)) {
|
|
136
|
-
|
|
280
|
+
targetNode = nodeWithName.name;
|
|
137
281
|
}
|
|
138
|
-
const t = checker.getTypeAtLocation(
|
|
139
|
-
return {
|
|
282
|
+
const t = checker.getTypeAtLocation(targetNode);
|
|
283
|
+
return {
|
|
284
|
+
signature: checker.typeToString(t, void 0, flags),
|
|
285
|
+
line: line + 1,
|
|
286
|
+
column: character + 1,
|
|
287
|
+
documentation,
|
|
288
|
+
kind,
|
|
289
|
+
name
|
|
290
|
+
};
|
|
140
291
|
}
|
|
141
292
|
|
|
142
293
|
// src/index.ts
|
|
143
|
-
function
|
|
144
|
-
const
|
|
145
|
-
const { line, project } = opts;
|
|
294
|
+
function hover(file, line, column, options) {
|
|
295
|
+
const { project, include_docs = false } = options ?? {};
|
|
146
296
|
const entryFileAbs = path2.resolve(process.cwd(), file);
|
|
147
297
|
if (!fs.existsSync(entryFileAbs)) {
|
|
148
298
|
throw new Error(`File not found: ${entryFileAbs}`);
|
|
@@ -154,14 +304,11 @@ function inferType(file, name, options) {
|
|
|
154
304
|
`Could not load source file into the program (check tsconfig include/exclude): ${entryFileAbs}`
|
|
155
305
|
);
|
|
156
306
|
}
|
|
157
|
-
const node =
|
|
307
|
+
const node = findNodeAtPosition(sourceFile, line, column);
|
|
158
308
|
if (!node) {
|
|
159
|
-
|
|
160
|
-
throw new Error(
|
|
161
|
-
`No symbol named "${name}"${lineInfo} found in ${entryFileAbs}`
|
|
162
|
-
);
|
|
309
|
+
throw new Error(`No symbol found at ${entryFileAbs}:${line}:${column}`);
|
|
163
310
|
}
|
|
164
|
-
return
|
|
311
|
+
return getHoverInfo(program, node, sourceFile, include_docs);
|
|
165
312
|
}
|
|
166
313
|
|
|
167
314
|
// src/cli.ts
|
|
@@ -169,24 +316,24 @@ var HELP = `
|
|
|
169
316
|
prinfer - TypeScript type inference inspection tool
|
|
170
317
|
|
|
171
318
|
Usage:
|
|
172
|
-
prinfer <file.ts>[
|
|
319
|
+
prinfer <file.ts>:<line>:<column> [--docs] [--project <tsconfig.json>]
|
|
173
320
|
prinfer setup
|
|
174
321
|
|
|
175
322
|
Commands:
|
|
176
323
|
setup Install MCP server and skill for Claude Code
|
|
177
324
|
|
|
178
325
|
Arguments:
|
|
179
|
-
file.ts
|
|
180
|
-
:line Optional line number to narrow search (e.g., file.ts:75)
|
|
181
|
-
name Name of the function/variable to inspect
|
|
326
|
+
file.ts:line:column Path to TypeScript file with 1-based line and column
|
|
182
327
|
|
|
183
328
|
Options:
|
|
329
|
+
--docs, -d Include JSDoc/TSDoc documentation
|
|
184
330
|
--project, -p Path to tsconfig.json (optional)
|
|
185
331
|
--help, -h Show this help message
|
|
186
332
|
|
|
187
333
|
Examples:
|
|
188
|
-
prinfer src/utils.ts
|
|
189
|
-
prinfer src/utils.ts:75
|
|
334
|
+
prinfer src/utils.ts:75:10
|
|
335
|
+
prinfer src/utils.ts:75:10 --docs
|
|
336
|
+
prinfer src/utils.ts:75:10 --project ./tsconfig.json
|
|
190
337
|
prinfer setup
|
|
191
338
|
`.trim();
|
|
192
339
|
var MANUAL_SETUP = `
|
|
@@ -232,26 +379,26 @@ When writing TypeScript code, prefer relying on type inference over explicit typ
|
|
|
232
379
|
- The type serves as documentation for complex structures
|
|
233
380
|
- You're defining a public API contract
|
|
234
381
|
|
|
235
|
-
Use the \`prinfer\` MCP tool (\`
|
|
382
|
+
Use the \`prinfer\` MCP tool (\`hover\`) to verify what TypeScript infers before adding explicit types.
|
|
236
383
|
|
|
237
384
|
## Commands
|
|
238
385
|
|
|
239
|
-
### /
|
|
386
|
+
### /hover
|
|
240
387
|
|
|
241
|
-
Check the inferred type
|
|
388
|
+
Check the inferred type at a specific position in a TypeScript file.
|
|
242
389
|
|
|
243
|
-
Usage: \`/
|
|
390
|
+
Usage: \`/hover <file>:<line>:<column>\`
|
|
244
391
|
|
|
245
392
|
Examples:
|
|
246
|
-
- \`/
|
|
247
|
-
- \`/
|
|
393
|
+
- \`/hover src/utils.ts:75:10\`
|
|
394
|
+
- \`/hover src/utils.ts:42:5\`
|
|
248
395
|
|
|
249
|
-
<command-name>
|
|
396
|
+
<command-name>hover</command-name>
|
|
250
397
|
|
|
251
|
-
Use the \`
|
|
252
|
-
1. Parse the arguments to extract file,
|
|
253
|
-
2. Call \`
|
|
254
|
-
3. Report the inferred signature
|
|
398
|
+
Use the \`hover\` MCP tool to check the type:
|
|
399
|
+
1. Parse the arguments to extract file, line, and column
|
|
400
|
+
2. Call \`hover(file, line, column, { include_docs: true })\`
|
|
401
|
+
3. Report the inferred signature, return type, and documentation
|
|
255
402
|
`;
|
|
256
403
|
function runSetup() {
|
|
257
404
|
const homeDir = os.homedir();
|
|
@@ -293,12 +440,16 @@ function runSetup() {
|
|
|
293
440
|
process.exit(1);
|
|
294
441
|
}
|
|
295
442
|
}
|
|
296
|
-
function
|
|
297
|
-
const match = arg.match(/^(.+):(\d+)$/);
|
|
443
|
+
function parsePositionArg(arg) {
|
|
444
|
+
const match = arg.match(/^(.+):(\d+):(\d+)$/);
|
|
298
445
|
if (match) {
|
|
299
|
-
return {
|
|
446
|
+
return {
|
|
447
|
+
file: match[1],
|
|
448
|
+
line: Number.parseInt(match[2], 10),
|
|
449
|
+
column: Number.parseInt(match[3], 10)
|
|
450
|
+
};
|
|
300
451
|
}
|
|
301
|
-
return
|
|
452
|
+
return null;
|
|
302
453
|
}
|
|
303
454
|
function parseArgs(argv) {
|
|
304
455
|
const args = argv.slice(2);
|
|
@@ -310,16 +461,17 @@ function parseArgs(argv) {
|
|
|
310
461
|
runSetup();
|
|
311
462
|
return null;
|
|
312
463
|
}
|
|
313
|
-
const
|
|
314
|
-
const
|
|
315
|
-
if (!
|
|
464
|
+
const positionArg = args[0];
|
|
465
|
+
const parsed = parsePositionArg(positionArg);
|
|
466
|
+
if (!parsed) {
|
|
316
467
|
console.error(
|
|
317
|
-
"Error:
|
|
468
|
+
"Error: Position argument must be in format <file>:<line>:<column>\n"
|
|
318
469
|
);
|
|
319
470
|
console.log(HELP);
|
|
320
471
|
process.exit(1);
|
|
321
472
|
}
|
|
322
|
-
const { file, line } =
|
|
473
|
+
const { file, line, column } = parsed;
|
|
474
|
+
const includeDocs = args.includes("--docs") || args.includes("-d");
|
|
323
475
|
let project;
|
|
324
476
|
const projectIdx = args.findIndex((a) => a === "--project" || a === "-p");
|
|
325
477
|
if (projectIdx >= 0) {
|
|
@@ -330,7 +482,7 @@ function parseArgs(argv) {
|
|
|
330
482
|
process.exit(1);
|
|
331
483
|
}
|
|
332
484
|
}
|
|
333
|
-
return { file,
|
|
485
|
+
return { file, line, column, includeDocs, project };
|
|
334
486
|
}
|
|
335
487
|
function main() {
|
|
336
488
|
const options = parseArgs(process.argv);
|
|
@@ -338,14 +490,21 @@ function main() {
|
|
|
338
490
|
process.exit(0);
|
|
339
491
|
}
|
|
340
492
|
try {
|
|
341
|
-
const result =
|
|
342
|
-
|
|
493
|
+
const result = hover(options.file, options.line, options.column, {
|
|
494
|
+
include_docs: options.includeDocs,
|
|
343
495
|
project: options.project
|
|
344
496
|
});
|
|
345
497
|
console.log(result.signature);
|
|
346
498
|
if (result.returnType) {
|
|
347
499
|
console.log("returns:", result.returnType);
|
|
348
500
|
}
|
|
501
|
+
if (result.name) {
|
|
502
|
+
console.log("name:", result.name);
|
|
503
|
+
}
|
|
504
|
+
console.log("kind:", result.kind);
|
|
505
|
+
if (result.documentation) {
|
|
506
|
+
console.log("docs:", result.documentation);
|
|
507
|
+
}
|
|
349
508
|
} catch (error) {
|
|
350
509
|
console.error(error.message);
|
|
351
510
|
process.exit(1);
|