Skip to main content
Glama
t09tanaka

TypeScript Rename Helper

by t09tanaka

planDirectoryMove

Plan TypeScript directory moves by analyzing import dependencies and generating edit plans without modifying files. Updates import paths recursively for all contained files.

Instructions

Plan directory move with recursive import updates for all contained files. Returns edit plans and file move suggestions without modifying the filesystem.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectRootYesAbsolute or relative path to the project root
oldDirYesAbsolute path or path relative to projectRoot of the directory to move
newDirYesAbsolute path or path relative to projectRoot of the destination

Implementation Reference

  • Core implementation of the planDirectoryMove tool. Normalizes paths, identifies TypeScript project files under the old directory, computes new file paths, uses the TypeScript Language Service to generate rename edits for imports/references, merges edits per file, and returns file text edits along with filesystem move operations.
    export function planDirectoryMove( params: PlanDirectoryMoveParams ): PlanDirectoryMoveResult { // 1. パスを絶対パスに正規化 const projectRootAbs = path.resolve(params.projectRoot); const oldDirAbs = path.isAbsolute(params.oldDir) ? path.resolve(params.oldDir) : path.resolve(projectRootAbs, params.oldDir); const newDirAbs = path.isAbsolute(params.newDir) ? path.resolve(params.newDir) : path.resolve(projectRootAbs, params.newDir); // 2. TypeScript Language Service を取得 const { service, parsedConfig } = createTsService(projectRootAbs); // 3. oldDir 配下のファイルだけを抽出 const targetFiles = parsedConfig.fileNames.filter((file) => { const normalizedFile = path.normalize(file); const normalizedOldDir = path.normalize(oldDirAbs); return normalizedFile.startsWith(normalizedOldDir + path.sep); }); // ファイルごとの編集をマージするためのマップ const editsMap = new Map<string, TextEdit[]>(); const fsMoves: FsMove[] = []; // 4-6. 各ファイルについて移動先を計算し、編集を取得 for (const oldFile of targetFiles) { // 4. newFile を計算 const rel = path.relative(oldDirAbs, oldFile); const newFile = path.join(newDirAbs, rel); // 5. service.getEditsForFileRename() を呼び出し const fileTextChanges = service.getEditsForFileRename( oldFile, newFile, /* formatOptions */ {}, /* preferences */ {} ); // 6. FileTextChanges を TextEdit に変換してマージ for (const change of fileTextChanges) { const fileName = change.fileName; const existingEdits = editsMap.get(fileName) ?? []; for (const textChange of change.textChanges) { // textChange.span を Range に変換 const fileText = ts.sys.readFile(fileName); if (!fileText) continue; const sourceFile = ts.createSourceFile( fileName, fileText, ts.ScriptTarget.Latest, true ); const start = ts.getLineAndCharacterOfPosition( sourceFile, textChange.span.start ); const end = ts.getLineAndCharacterOfPosition( sourceFile, textChange.span.start + textChange.span.length ); const textEdit: TextEdit = { range: { start: { line: start.line, character: start.character, }, end: { line: end.line, character: end.character, }, }, newText: textChange.newText, }; existingEdits.push(textEdit); } editsMap.set(fileName, existingEdits); } // 7. fsMoves にペアを追加 fsMoves.push({ from: oldFile, to: newFile, }); } // editsMap を FileTextEdits[] に変換 const edits: FileTextEdits[] = Array.from(editsMap.entries()).map( ([filePath, textEdits]) => ({ filePath, textEdits, }) ); // 8. 結果を返す return { edits, fsMoves, }; }
  • src/index.ts:94-118 (registration)
    Registers the planDirectoryMove tool in the MCP server's TOOLS list, defining its name, description, and JSON input schema for validation.
    { name: "planDirectoryMove", description: "Plan directory move with recursive import updates for all contained files. Returns edit plans and file move suggestions without modifying the filesystem.", inputSchema: { type: "object", properties: { projectRoot: { type: "string", description: "Absolute or relative path to the project root", }, oldDir: { type: "string", description: "Absolute path or path relative to projectRoot of the directory to move", }, newDir: { type: "string", description: "Absolute path or path relative to projectRoot of the destination", }, }, required: ["projectRoot", "oldDir", "newDir"], }, },
  • src/index.ts:177-188 (registration)
    Dispatches calls to the planDirectoryMove handler in the MCP tool request switch statement.
    case "planDirectoryMove": { const params = args as unknown as PlanDirectoryMoveParams; const result = planDirectoryMove(params); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }
  • TypeScript type definitions for the input parameters and output result of the planDirectoryMove tool.
    * planDirectoryMove の入力パラメータ */ export type PlanDirectoryMoveParams = { projectRoot: string; // 絶対 or 相対 oldDir: string; // 元ディレクトリパス newDir: string; // 移動先ディレクトリパス }; /** * planDirectoryMove の出力結果 */ export type PlanDirectoryMoveResult = { edits: FileTextEdits[]; fsMoves: FsMove[]; };

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/t09tanaka/ts-rename-helper-mcp'

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