109 lines
4 KiB
TypeScript
Executable file
109 lines
4 KiB
TypeScript
Executable file
import { Project, SyntaxKind } from 'ts-morph';
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
|
|
const project = new Project({
|
|
tsConfigFilePath: 'C:/ScriptoriumAI/scriptoriumai-ui/tsconfig.json'
|
|
});
|
|
|
|
const sourceFile = project.getSourceFileOrThrow('src/pages/Runboard.tsx');
|
|
const destFilePath = 'src/utils/runboard-route-logic.tsx';
|
|
let destFile = project.getSourceFile(destFilePath);
|
|
if (destFile) destFile.deleteImmediatelySync();
|
|
destFile = project.createSourceFile(destFilePath);
|
|
|
|
// Find export function Runboard
|
|
const runboardNode = sourceFile.getFunction('Runboard');
|
|
if (!runboardNode) throw new Error('Runboard not found!');
|
|
|
|
const runboardPos = runboardNode.getStart();
|
|
|
|
// Collect all statements before Runboard
|
|
const statements = sourceFile.getStatements();
|
|
const toMove = statements.filter(stmt => stmt.getStart() < runboardPos && stmt.getKindName() !== 'ImportDeclaration');
|
|
|
|
const movedNames: string[] = [];
|
|
|
|
toMove.forEach(stmt => {
|
|
// If it's a dec we can export it
|
|
if (stmt.isKind(SyntaxKind.VariableStatement) ||
|
|
stmt.isKind(SyntaxKind.FunctionDeclaration) ||
|
|
stmt.isKind(SyntaxKind.TypeAliasDeclaration) ||
|
|
stmt.isKind(SyntaxKind.InterfaceDeclaration)) {
|
|
|
|
// Force export
|
|
if (!stmt.hasExportKeyword()) {
|
|
// stmt.setIsExported(true); this requires casting
|
|
(stmt as any).setIsExported?.(true);
|
|
}
|
|
|
|
if (stmt.isKind(SyntaxKind.VariableStatement)) {
|
|
stmt.getDeclarations().forEach(d => movedNames.push(d.getName()));
|
|
} else {
|
|
const name = (stmt as any).getName?.();
|
|
if (name) movedNames.push(name);
|
|
}
|
|
|
|
destFile.addStatements(stmt.getText());
|
|
stmt.remove();
|
|
}
|
|
});
|
|
|
|
// Update imports in destFile (lazy way: just copy them all and let eslint/ts-morph sort out unused later, but we can do it explicitly)
|
|
const imports = sourceFile.getImportDeclarations();
|
|
imports.forEach(imp => {
|
|
// We adjust relative paths up one level
|
|
const moduleSpec = imp.getModuleSpecifierValue();
|
|
let newModule = moduleSpec;
|
|
if (newModule.startsWith('./')) {
|
|
newModule = '../pages/' + newModule.substring(2);
|
|
}
|
|
// Just copy all imports to destFile
|
|
destFile.addImportDeclaration({
|
|
isTypeOnly: imp.isTypeOnly(),
|
|
defaultImport: imp.getDefaultImport()?.getText(),
|
|
namedImports: imp.getNamedImports().map(ni => ({ name: ni.getName(), alias: ni.getAliasNode()?.getText() })),
|
|
moduleSpecifier: newModule
|
|
});
|
|
});
|
|
|
|
// Now import the extracted names back into Runboard
|
|
const uniqueNames = Array.from(new Set(movedNames));
|
|
sourceFile.addImportDeclaration({
|
|
namedImports: uniqueNames,
|
|
moduleSpecifier: '../utils/runboard-route-logic'
|
|
});
|
|
|
|
// Replace test imports
|
|
const testFiles = project.getSourceFiles('src/__tests__/**/*.{ts,tsx}');
|
|
testFiles.forEach(testFile => {
|
|
const testImports = testFile.getImportDeclarations();
|
|
testImports.forEach(imp => {
|
|
const mod = imp.getModuleSpecifierValue();
|
|
if (mod === '../pages/Runboard' || mod === '../../pages/Runboard') {
|
|
// Check if it imports Runboard itself
|
|
const named = imp.getNamedImports();
|
|
const hasRunboard = named.some(n => n.getName() === 'Runboard');
|
|
const otherImports = named.filter(n => n.getName() !== 'Runboard');
|
|
|
|
if (otherImports.length > 0) {
|
|
// Add new import for logic
|
|
const logicMod = mod.replace('pages/Runboard', 'utils/runboard-route-logic');
|
|
testFile.addImportDeclaration({
|
|
namedImports: otherImports.map(n => ({ name: n.getName(), alias: n.getAliasNode()?.getText() })),
|
|
moduleSpecifier: logicMod
|
|
});
|
|
}
|
|
|
|
if (hasRunboard) {
|
|
// Remove other imports from existing
|
|
otherImports.forEach(n => n.remove());
|
|
} else {
|
|
imp.remove();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
project.saveSync();
|
|
console.log('Successfully factored Runboard dependencies using ts-morph!');
|