Skip to main content
Glama
SiroSuzume

MCP ts-morph Refactoring Tools

by SiroSuzume
find-references.ts3.38 kB
import type { Node, SourceFile } from "ts-morph"; import { initializeProject } from "./_utils/ts-morph-project"; import { findIdentifierNode } from "./rename-symbol/rename-symbol"; // --- Data Structure for Result --- export interface ReferenceLocation { filePath: string; line: number; column: number; text: string; } // --- Main Function --- /** * 指定された位置にあるシンボルの参照箇所をプロジェクト全体から検索する */ export async function findSymbolReferences({ tsconfigPath, targetFilePath, position, }: { tsconfigPath: string; targetFilePath: string; position: { line: number; column: number }; }): Promise<{ references: ReferenceLocation[]; definition: ReferenceLocation | null; }> { const project = initializeProject(tsconfigPath); // targetFilePath は絶対パスである想定 const identifierNode = findIdentifierNode(project, targetFilePath, position); // findReferencesAsNodes() は定義箇所を含まない場合がある const referenceNodes: Node[] = identifierNode.findReferencesAsNodes(); let definitionLocation: ReferenceLocation | null = null; const definitions = identifierNode.getDefinitionNodes(); if (definitions.length > 0) { const defNode = definitions[0]; const defSourceFile = defNode.getSourceFile(); const defStartPos = defNode.getStart(); const { line: defLine, column: defColumn } = defSourceFile.getLineAndColumnAtPos(defStartPos); const lineText = getLineText(defSourceFile, defLine); definitionLocation = { filePath: defSourceFile.getFilePath(), line: defLine, column: defColumn, text: lineText.trim(), }; } const references: ReferenceLocation[] = []; for (const refNode of referenceNodes) { const refSourceFile = refNode.getSourceFile(); const refStartPos = refNode.getStart(); const { line: refLine, column: refColumn } = refSourceFile.getLineAndColumnAtPos(refStartPos); if ( definitionLocation && refLine !== undefined && refColumn !== undefined && refSourceFile.getFilePath() === definitionLocation.filePath && refLine === definitionLocation.line && refColumn === definitionLocation.column ) { continue; // 定義箇所と同じであればスキップ } if (refLine === undefined || refColumn === undefined) continue; const filePath = refSourceFile.getFilePath(); const lineText = getLineText(refSourceFile, refLine); references.push({ filePath, line: refLine, column: refColumn, text: lineText.trim(), }); } references.sort((a, b) => { if (a.filePath !== b.filePath) { return a.filePath.localeCompare(b.filePath); } return a.line - b.line; }); return { references, definition: definitionLocation }; } function getLineText(sourceFile: SourceFile, lineNumber: number): string { // ファイル全体のテキストを取得し、行で分割して該当行を返す const lines = sourceFile.getFullText().split(/\r?\n/); // lineNumber は 1-based なので、インデックスは lineNumber - 1 if (lineNumber > 0 && lineNumber <= lines.length) { return lines[lineNumber - 1]; } // 該当行が見つからない場合、エラーとするか、空文字列を返すかなどの仕様による // ここではエラーを投げるのが自然かもしれない throw new Error( `Line ${lineNumber} not found in file ${sourceFile.getFilePath()}`, ); }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/SiroSuzume/mcp-ts-morph'

If you have feedback or need assistance with the MCP directory API, please join our Discord server