← スキル一覧に戻る

ts-morph-refactoring
by robBowes
⭐ 0🍴 0📅 2026年1月13日
SKILL.md
name: ts-morph-refactoring description: TypeScript refactoring using ts-morph in pnpm monorepos. Use when renaming variables, functions, classes, or types across packages; updating imports; moving files; or performing codemod operations. Triggers on requests involving TypeScript AST manipulation, bulk code changes, or cross-package refactoring.
ts-morph Refactoring in pnpm Monorepos
Setup
import { Project } from "ts-morph";
const project = new Project({
tsConfigFilePath: "./tsconfig.json", // Root tsconfig with project references
});
// For monorepo: add all package tsconfigs
project.addSourceFilesFromTsConfig("./packages/*/tsconfig.json");
Rename Variable/Function
const sourceFile = project.getSourceFileOrThrow("src/utils.ts");
// Find and rename
const fn = sourceFile.getFunctionOrThrow("oldName");
fn.rename("newName"); // Updates all references across project
// For exports - also updates import statements
const exportedFn = sourceFile.getExportedDeclarations().get("oldExport")?.[0];
exportedFn?.asKind(SyntaxKind.FunctionDeclaration)?.rename("newExport");
project.saveSync();
Rename Across Packages
// Find declaration in any package
const declaration = project.getSourceFiles()
.flatMap(sf => sf.getExportedDeclarations().get("targetName") ?? [])
.find(d => d.getSourceFile().getFilePath().includes("packages/shared"));
declaration?.asKind(SyntaxKind.FunctionDeclaration)?.rename("newTargetName");
// All imports in all packages update automatically
project.saveSync();
Update Import Paths
// Change import path across all files
project.getSourceFiles().forEach(sourceFile => {
sourceFile.getImportDeclarations().forEach(imp => {
const moduleSpec = imp.getModuleSpecifierValue();
if (moduleSpec === "@old/package") {
imp.setModuleSpecifier("@new/package");
}
// Relative path updates
if (moduleSpec.startsWith("../old-folder/")) {
imp.setModuleSpecifier(moduleSpec.replace("../old-folder/", "../new-folder/"));
}
});
});
project.saveSync();
Add/Remove Named Imports
sourceFile.getImportDeclarations().forEach(imp => {
if (imp.getModuleSpecifierValue() === "@company/utils") {
// Add named import
imp.addNamedImport("newUtil");
// Remove named import
imp.getNamedImports()
.find(n => n.getName() === "deprecatedUtil")
?.remove();
// Rename named import
imp.getNamedImports()
.find(n => n.getName() === "oldUtil")
?.setName("renamedUtil");
}
});
Move Export Between Packages
// Get source declaration
const srcFile = project.getSourceFileOrThrow("packages/old/src/helper.ts");
const fn = srcFile.getFunctionOrThrow("helperFn");
const fnText = fn.getFullText();
// Add to destination
const destFile = project.getSourceFileOrThrow("packages/new/src/helper.ts");
destFile.addStatements(fnText);
// Update all imports
project.getSourceFiles().forEach(sf => {
sf.getImportDeclarations()
.filter(i => i.getModuleSpecifierValue() === "@company/old")
.forEach(imp => {
const namedImport = imp.getNamedImports().find(n => n.getName() === "helperFn");
if (namedImport) {
namedImport.remove();
if (imp.getNamedImports().length === 0) imp.remove();
// Add new import if not exists
const existingNew = sf.getImportDeclaration("@company/new");
if (existingNew) {
existingNew.addNamedImport("helperFn");
} else {
sf.addImportDeclaration({
moduleSpecifier: "@company/new",
namedImports: ["helperFn"]
});
}
}
});
});
// Remove from source after updating imports
fn.remove();
project.saveSync();
Common Patterns
Find All References
const refs = declaration.findReferencesAsNodes();
refs.forEach(ref => console.log(ref.getSourceFile().getFilePath(), ref.getStartLineNumber()));
Batch Rename Pattern
const renames = [["oldA", "newA"], ["oldB", "newB"]];
renames.forEach(([old, new_]) => {
project.getSourceFiles().forEach(sf => {
sf.getExportedDeclarations().get(old)?.[0]
?.asKind(SyntaxKind.FunctionDeclaration)?.rename(new_);
});
});
project.saveSync();
Dry Run
// Preview changes without saving
project.getSourceFiles().forEach(sf => {
if (sf.wasSaved() === false) {
console.log(`Would modify: ${sf.getFilePath()}`);
console.log(sf.getFullText());
}
});
Notes
- Always use
project.saveSync()after refactoring rename()handles cross-file references automatically- For pnpm workspaces: ensure root tsconfig has
referencesto all packages - Use
SyntaxKindenum for type narrowing:import { SyntaxKind } from "ts-morph"
スコア
総合スコア
50/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
レビュー
💬
レビュー機能は近日公開予定です