mirror of
https://github.com/johndoe6345789/tsmorph.git
synced 2026-04-24 13:54:58 +00:00
183 lines
5.5 KiB
TypeScript
183 lines
5.5 KiB
TypeScript
#!/usr/bin/env ts-node
|
|
|
|
import { Project, SyntaxKind, SourceFile, VariableDeclaration } from 'ts-morph';
|
|
import * as path from 'path';
|
|
|
|
/**
|
|
* Second pass: Extract utility functions from inside the component
|
|
* This extracts helper functions like validateForm, getRoleBadgeColor, etc.
|
|
*/
|
|
|
|
class TSXRefactorer2 {
|
|
private project: Project;
|
|
private sourceFile: SourceFile;
|
|
|
|
constructor(filePath: string) {
|
|
this.project = new Project({
|
|
tsConfigFilePath: path.join(__dirname, '..', 'tsconfig.json'),
|
|
});
|
|
|
|
this.sourceFile = this.project.addSourceFileAtPath(filePath);
|
|
}
|
|
|
|
/**
|
|
* Extract helper functions that don't use hooks or state
|
|
*/
|
|
extractHelperFunctions(): void {
|
|
console.log('\n🔄 Extracting helper functions (2nd pass)...');
|
|
|
|
const utilsFilePath = this.sourceFile.getFilePath().replace('.tsx', '.utils.ts');
|
|
|
|
// Find the main component
|
|
const componentDecl = this.sourceFile.getVariableDeclaration('UserManagementDashboard');
|
|
if (!componentDecl) {
|
|
console.log(' ⚠️ Could not find component');
|
|
return;
|
|
}
|
|
|
|
const arrowFunc = componentDecl.getInitializerIfKind(SyntaxKind.ArrowFunction);
|
|
if (!arrowFunc) {
|
|
console.log(' ⚠️ Component is not an arrow function');
|
|
return;
|
|
}
|
|
|
|
const body = arrowFunc.getBody();
|
|
if (!body || !body.isKind(SyntaxKind.Block)) {
|
|
console.log(' ⚠️ Component body not found');
|
|
return;
|
|
}
|
|
|
|
// Find helper functions inside the component
|
|
const helperFunctions: Array<{ name: string; text: string }> = [];
|
|
|
|
// Look for const declarations with arrow functions
|
|
const block = body.asKind(SyntaxKind.Block);
|
|
if (!block) return;
|
|
|
|
const statements = block.getStatements();
|
|
|
|
statements.forEach(stmt => {
|
|
if (stmt.isKind(SyntaxKind.VariableStatement)) {
|
|
const declarations = stmt.getDeclarations();
|
|
|
|
declarations.forEach(decl => {
|
|
const name = decl.getName();
|
|
const initializer = decl.getInitializer();
|
|
|
|
// Check if it's a helper function (arrow function that doesn't use hooks)
|
|
if (initializer && initializer.isKind(SyntaxKind.ArrowFunction)) {
|
|
const text = stmt.getText();
|
|
|
|
// Extract these specific helper functions
|
|
if (name.match(/^(validate|getRoleBadgeColor|getStatusBadgeColor|formatDate)/)) {
|
|
helperFunctions.push({ name, text });
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
if (helperFunctions.length === 0) {
|
|
console.log(' ⏭️ No helper functions to extract');
|
|
return;
|
|
}
|
|
|
|
// Read existing utils file or create new content
|
|
let utilsContent = '';
|
|
try {
|
|
const existingUtils = this.project.getSourceFile(utilsFilePath);
|
|
if (existingUtils) {
|
|
utilsContent = existingUtils.getFullText();
|
|
}
|
|
} catch (e) {
|
|
// File doesn't exist yet
|
|
utilsContent = [
|
|
'/**',
|
|
' * Extracted utility functions',
|
|
' * Auto-generated by ts-morph refactoring script',
|
|
' */',
|
|
'',
|
|
"import type { FormData, ValidationErrors, User } from './UserManagementDashboard.types';",
|
|
'',
|
|
].join('\n');
|
|
}
|
|
|
|
// Add the helper functions
|
|
const exportedFunctions = helperFunctions.map(func => {
|
|
// Make it exported
|
|
const exportedText = func.text.replace(/^(\s*)(const|let|var)/, '$1export const');
|
|
console.log(` ✓ Extracted: ${func.name}`);
|
|
return exportedText;
|
|
});
|
|
|
|
utilsContent += '\n' + exportedFunctions.join('\n\n');
|
|
|
|
// Write the utils file
|
|
const utilsFile = this.project.createSourceFile(utilsFilePath, utilsContent, { overwrite: true });
|
|
utilsFile.saveSync();
|
|
|
|
// Remove helper functions from component and add imports
|
|
const functionNames = helperFunctions.map(f => f.name);
|
|
|
|
statements.forEach(stmt => {
|
|
if (stmt.isKind(SyntaxKind.VariableStatement)) {
|
|
const declarations = stmt.getDeclarations();
|
|
declarations.forEach(decl => {
|
|
const name = decl.getName();
|
|
if (functionNames.includes(name)) {
|
|
stmt.remove();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Add import
|
|
const existingImport = this.sourceFile.getImportDeclaration('./UserManagementDashboard.utils');
|
|
if (existingImport) {
|
|
// Remove existing and recreate with combined imports
|
|
const namedImports = existingImport.getNamedImports().map(ni => ni.getName());
|
|
const newImports = [...new Set([...namedImports, ...functionNames])];
|
|
existingImport.remove();
|
|
this.sourceFile.addImportDeclaration({
|
|
moduleSpecifier: './UserManagementDashboard.utils',
|
|
namedImports: newImports,
|
|
});
|
|
} else {
|
|
// Create new import
|
|
this.sourceFile.addImportDeclaration({
|
|
moduleSpecifier: './UserManagementDashboard.utils',
|
|
namedImports: functionNames,
|
|
});
|
|
}
|
|
|
|
this.sourceFile.saveSync();
|
|
console.log(` 💾 Saved: ${path.basename(utilsFilePath)}`);
|
|
}
|
|
|
|
save(): void {
|
|
this.sourceFile.saveSync();
|
|
console.log('\n✅ Second pass refactoring complete!');
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
console.log('🚀 TSX Refactoring Tool - Second Pass\n');
|
|
|
|
const targetFile = path.join(
|
|
__dirname,
|
|
'..',
|
|
'src',
|
|
'components',
|
|
'UserManagementDashboard.tsx'
|
|
);
|
|
|
|
const refactorer = new TSXRefactorer2(targetFile);
|
|
refactorer.extractHelperFunctions();
|
|
refactorer.save();
|
|
|
|
console.log('\n💡 Helper functions extracted!');
|
|
console.log(' - Run npm run type-check to verify');
|
|
}
|
|
|
|
main().catch(console.error);
|