create-kt-plugin
Version:
A template for creating a KT plugins for ExtendScript
245 lines (229 loc) • 7.86 kB
text/typescript
import inquirer from 'inquirer';
import fs from 'fs/promises';
import path from 'path';
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
async function createPlugin() {
// Pregunta al usuario
const answers = await inquirer.prompt([
{
type: 'input',
name: 'pluginName',
message: '¿Wich is the name of your plugin?',
default: 'MyPlugin',
validate: (input) =>
/^[a-zA-Z0-9-]+$/.test(input) ||
'Only letters, numbers and hyphens are allowed'
},
{
type: 'list',
name: 'targetProgram',
message: '¿Wich is the target program?',
choices: [
'AfterEffects',
'ExtendScript',
'Photoshop',
'Premiere',
'Illustrator'
],
default: 'AfterEffects'
},
{
type: 'list',
name: 'appVersion',
message: '¿Wich is the target app version?',
when: (answers) => answers.targetProgram !== 'ExtendScript',
choices: async (answers) => {
const versions = await getAppAvailableVersions(
answers.targetProgram
);
return versions;
},
default: '23.0'
},
{
type: 'input',
name: 'author',
message: '¿Author?',
default: ''
},
{
type: 'input',
name: 'description',
message: '¿Description?',
default: ''
},
{
type: 'confirm',
name: 'installDeps',
message: '¿Install dependencies?',
default: true
}
]);
const { pluginName, targetProgram, installDeps, appVersion } = answers;
const sourceDir = path.join(__dirname, '../template');
const targetDir = path.resolve(process.cwd(), pluginName);
const ktDependencies: string[] = ['kt-core'];
try {
// Copia la carpeta template
await fs.mkdir(targetDir, { recursive: true });
await copyDir(
sourceDir,
targetDir,
pluginName,
answers.author,
answers.description,
ktDependencies,
targetProgram,
appVersion
);
console.log(`Project "${pluginName}" created at ${targetDir}`);
// Instala dependencias si se seleccionó
if (installDeps) {
console.log('Installing dependencias...');
await execAsync('npm install', { cwd: targetDir });
console.log('Dependencias instaladas');
} else {
console.log(
'Type "cd ' +
pluginName +
' && npm install" to install dependencies'
);
}
} catch (err) {
console.error('Error building the project:', err);
}
}
async function copyDir(
src: string,
dest: string,
pluginName: string,
author: string = '',
description: string = '',
ktDependencies: string[] = [],
targetProgram: string,
appVersion: string
) {
const entries = await fs.readdir(src, { withFileTypes: true });
const kebapName = toKebabCase(pluginName);
const upperCamelName = toUpperCamelCase(pluginName);
for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const newName = entry.name.replace('MyPlugin', upperCamelName);
const destPath = path.join(dest, newName);
const name = entry.name;
if (entry.isDirectory()) {
await fs.mkdir(destPath, { recursive: true });
await copyDir(
srcPath,
destPath,
pluginName,
author,
description,
ktDependencies,
targetProgram,
appVersion
);
} else {
const content = await fs.readFile(srcPath, 'utf-8');
let newContent = content;
if (entry.name === 'package.json') {
newContent = await modifyPackageJson(
newContent,
kebapName,
author,
description,
ktDependencies
);
} else if (
entry.name === 'tsconfig.json' &&
targetProgram !== 'ExtendScript'
) {
newContent = addAppTypesToTsConfig(
newContent,
targetProgram,
appVersion
);
} else {
newContent = newContent.replace(/MyPlugin/g, upperCamelName);
}
await fs.writeFile(destPath, newContent);
}
}
}
function toCamelCase(str: string) {
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
}
function toUpperCamelCase(str: string) {
return toCamelCase(str).replace(/^[a-z]/, (letter) => letter.toUpperCase());
}
function toKebabCase(str: string) {
return str.replace(/[A-Z]/g, (letter) => '-' + letter.toLowerCase());
}
async function modifyPackageJson(
content: string,
name: string,
author: string = '',
description: string = '',
ktDependencies: string[] = []
) {
const config = JSON.parse(content);
config.dependencies = config.dependencies || {};
ktDependencies.forEach((dep) => {
config.dependencies[dep] = '*';
});
config.name = name;
config.author = author;
config.description = description;
config.version = '1.0.0';
const newContent = JSON.stringify(config, null, 2);
return newContent;
}
// function modifyViteConfig(content: string, ktDependencies: string[] = []) {
// //modify "exclude: /node_modules/" to include kt dependencies"
// const newContent = content.replace(
// /exclude: \/node_modules\//,
// `exclude: /node_modules\\/(?!${ktDependencies.join('|')})/`
// );
// return newContent;
// }
async function getAppAvailableVersions(app: string) {
const typesForAdobePath = path.dirname(
require.resolve('types-for-adobe/package.json')
);
const appPath = path.join(typesForAdobePath, app);
console.log('Finding verions:', appPath);
try {
const appDir = await fs.readdir(appPath, { withFileTypes: true });
if (!appDir || appDir.length === 0) {
throw new Error(`App ${app} not found or empty`);
}
const versions = appDir
.filter((dir) => dir.isDirectory())
.map((dir) => dir.name);
return versions;
} catch (err) {
console.error('Error al leer versiones:', err);
return ['Unknown'];
}
}
function addAppTypesToTsConfig(content: string, app: string, version: string) {
const appPath = `./node_modules/types-for-adobe/${app}/${version}`;
const tsconfig = JSON.parse(content);
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
tsconfig.compilerOptions.types = tsconfig.compilerOptions.types || [];
let alreadyAdded = false;
for (const type of tsconfig.compilerOptions.types) {
if (type === appPath) {
alreadyAdded = true;
break;
}
}
if (!alreadyAdded) {
tsconfig.compilerOptions.types.push(appPath);
}
return JSON.stringify(tsconfig, null, 2);
}
createPlugin();