Files

106 lines
4.0 KiB
JavaScript

import { Project, SyntaxKind } from "ts-morph";
import * as fs from "fs";
import * as path from "path";
const project = new Project();
const implFilePath = "src/preview/ops/implementation.ts";
const implFile = project.addSourceFileAtPath(implFilePath);
const mappings = {
"src/preview/ops/geometry.ts": [
"crop", "cropGeneric", "cropReformat", "cropStitch", "pad", "padOut",
"resize", "transform", "flipRotate", "cornerPin", "cameraShake", "distort", "spherize"
],
"src/preview/ops/blend.ts": [
"merge", "composite", "comp"
],
"src/preview/ops/masks.ts": [
"imageOpsMask", "channelApply"
],
"src/preview/ops/procedural.ts": [
"constant", "ramp", "noise", "grain", "text", "draw", "drawMask", "keyer", "stitch"
],
"src/preview/ops/video.ts": [
"channelSplit", "channelMerge"
]
};
const opsObjDecl = implFile.getVariableDeclarationOrThrow("ops");
const opsObj = opsObjDecl.getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
// Export all functions in implementation.ts so they can be imported
for (const func of implFile.getFunctions()) {
if (!func.isExported()) {
func.setIsExported(true);
}
}
let importsToAdd = {};
for (const [filePath, funcs] of Object.entries(mappings)) {
let extractedCode = "";
let extractedFuncs = [];
for (const prop of opsObj.getProperties()) {
if (prop.isKind(SyntaxKind.MethodDeclaration)) {
const name = prop.getName();
if (funcs.includes(name)) {
console.log(`Extracting ${name} to ${filePath}...`);
const text = prop.getText();
// Change methodName(...) or async methodName(...) to export [async] function methodName(...)
const isAsync = prop.isAsync() ? "async " : "";
// We use a regex that matches either name( or async name(
const regex = new RegExp(`^(async\\s+)?${name}\\s*\\(`);
const funcText = text.replace(regex, `export ${isAsync}function ${name}(`);
extractedCode += funcText + "\n\n";
extractedFuncs.push(name);
// Replace the method in opsObj with a property assignment
prop.replaceWithText(`${name}`);
}
}
}
if (extractedCode) {
let destFile = project.addSourceFileAtPathIfExists(filePath);
if (!destFile) {
destFile = project.createSourceFile(filePath, "");
}
// Remove existing Extracted comment and below if script was run before
const currentText = destFile.getFullText();
const splitIndex = currentText.indexOf("// Extracted with ts-morph");
let newText = splitIndex !== -1 ? currentText.substring(0, splitIndex) : currentText;
// Ensure imports exist
if (!newText.includes("import type { ComfyNode }")) {
newText = `import type { ComfyNode } from "../../types.js";\n` + newText;
}
if (!newText.includes("import * as impl")) {
newText = `import * as impl from "./implementation.js";\n` + newText;
// Also need to rewrite the function body to use impl. for missing references, but that's too complex.
// A simpler approach: we'll just let the user fix the imports or we do it manually after.
}
destFile.replaceWithText(newText + "\n\n// Extracted with ts-morph\n\n" + extractedCode);
destFile.saveSync();
console.log(`Successfully appended to ${filePath}!`);
const moduleName = "./" + path.basename(filePath, ".ts") + ".js";
importsToAdd[moduleName] = extractedFuncs;
}
}
// Add imports to implementation.ts
for (const [moduleName, funcs] of Object.entries(importsToAdd)) {
implFile.addImportDeclaration({
namedImports: funcs,
moduleSpecifier: moduleName
});
}
implFile.saveSync();
console.log("Refactoring complete!");