cbt-game-generator
Version:
Configuration generator for CBT animation apps
243 lines (201 loc) • 9.15 kB
text/typescript
import * as fs from 'fs';
import * as path from 'path';
export class FileUpdater {
constructor(
private gamePath: string,
private gameName: string,
private numberOfVariants: number
) {}
updateTypes(subLoIndex: number, isIncremental = false): void {
// Skip if this is sub-lo-1 and the directory exists
if (subLoIndex === 0 && this.doesSubLoDirectoryExist(1)) {
return;
}
this.updateTagTypes(subLoIndex);
}
private updateTagTypes(subLoIndex: number): void {
const tagTypesPath = path.join(this.gamePath, 'types', 'tagTypes.ts');
const content = fs.readFileSync(tagTypesPath, 'utf-8');
// Add new variant types
const startVariant = subLoIndex * this.numberOfVariants + 1;
const newTypes = Array.from({ length: this.numberOfVariants }, (_, i) => {
const variantNumber = startVariant + i;
return ` | I${this.gameName}<E${this.gameName}Variants.V${variantNumber}>`;
}).join('\n');
// Insert new types before the closing semicolon
const updatedContent = content.replace(
/(\s+};)/,
`${newTypes}\n$1`
);
fs.writeFileSync(tagTypesPath, updatedContent);
}
updateConstants(subLoIndex: number, targets: string[]): void {
// Skip if this is sub-lo-1 and the directory exists
if (subLoIndex === 0 && this.doesSubLoDirectoryExist(1)) {
return;
}
this.updateTargets(targets);
this.updateVariantsConfig(subLoIndex, targets);
}
private updateTargets(targets: string[]): void {
const targetsPath = path.join(this.gamePath, 'constants', 'targets.ts');
const content = fs.readFileSync(targetsPath, 'utf-8');
// Add new targets
const newTargets = targets.map(target => ` ${target} = "${target}",`).join('\n');
// Insert new targets before the closing brace
const updatedContent = content.replace(
/(\s+})/,
`${newTargets}\n$1`
);
fs.writeFileSync(targetsPath, updatedContent);
}
private updateVariantsConfig(subLoIndex: number, targets: string[]): void {
const variantsConfigPath = path.join(this.gamePath, 'constants', 'variantsConfig.ts');
const content = fs.readFileSync(variantsConfigPath, 'utf-8');
// Add new variants to the enum
const startVariant = subLoIndex * this.numberOfVariants + 1;
const newVariants = Array.from({ length: this.numberOfVariants }, (_, i) => {
const variantNumber = startVariant + i;
return ` V${variantNumber} = "${this.generateUniqueId()}",`;
}).join('\n');
// Add new target-based properties
const newProperties = targets.map(target => {
const properties = [
` ${target}_LOTTIE`,
` ${target}_WEBP`,
` ${target}_AUDIO`,
` ${target}_FACE_PROMPT`,
` ${target}_FACE_PROMPT_HALF`
];
return properties.join(',\n');
}).join(',\n');
// Add new config and mapping
const newConfig = `export const ${this.gameName.toLowerCase()}ConfigV${subLoIndex + 1}: Record<string, any> = {
${targets.map(target => ` ${target}: "${target}",`).join('\n')}
};
export const assetLottieWebpMappingSubLo${subLoIndex + 1}: Record<string, AssetsMapping[]> = {
${targets.map(target => ` ${target}: [
{
backgroundWebp: "${target.toLowerCase()}.webp",
lottie: "${target.toLowerCase()}.json",
facePrompt: "${target.toLowerCase()}.mp4",
halfFacePrompt: "${target.toLowerCase()}_half.mp4",
},
],`).join('\n')}
};`;
// Update content in multiple steps
let updatedContent = content;
// 1. Add new variants to the enum - preserve existing ones
const enumMatch = content.match(/enum\s+E\w+Variants\s*{([^}]*)}/);
if (enumMatch) {
const existingVariants = enumMatch[1].trim();
const updatedEnum = `enum E${this.gameName}Variants {\n${existingVariants}\n${newVariants}\n}`;
updatedContent = content.replace(/enum\s+E\w+Variants\s*{[^}]*}/, updatedEnum);
}
// 2. Add new properties - preserve existing ones
const propertiesMatch = content.match(/THIS_IS_A_AUDIO,\s*([^;]*);/);
if (propertiesMatch) {
const existingProperties = propertiesMatch[1].trim();
const updatedProperties = `THIS_IS_A_AUDIO,\n${existingProperties},\n${newProperties};`;
updatedContent = updatedContent.replace(/THIS_IS_A_AUDIO,\s*[^;]*;/, updatedProperties);
}
// 3. Add new config and mapping - append to existing ones
updatedContent = updatedContent + '\n\n' + newConfig;
fs.writeFileSync(variantsConfigPath, updatedContent);
}
updateMain(subLoIndex: number): void {
// Skip if this is sub-lo-1 and the directory exists
if (subLoIndex === 0 && this.doesSubLoDirectoryExist(1)) {
return;
}
const mainPath = path.join(this.gamePath, 'Main.tsx');
const content = fs.readFileSync(mainPath, 'utf-8');
// Add new imports
const startVariant = subLoIndex * this.numberOfVariants + 1;
const newImports = Array.from({ length: this.numberOfVariants }, (_, i) => {
const variantNumber = startVariant + i;
return `import { ${this.gameName}V${variantNumber} } from "./configuration/variants-config/sub-lo-${subLoIndex + 1}/${this.gameName}V${variantNumber}";`;
}).join('\n');
// Add new switch cases
const newCases = Array.from({ length: this.numberOfVariants }, (_, i) => {
const variantNumber = startVariant + i;
return ` case E${this.gameName}Variants.V${variantNumber}:
gameWithVariantConfig = ${this.gameName}V${variantNumber};
break;`;
}).join('\n');
// Update content
let updatedContent = content.replace(
/(import.*\n)(export default)/,
`$1${newImports}\n$2`
);
updatedContent = updatedContent.replace(
/(default:.*\n\s+break;)/,
`${newCases}\n$1`
);
fs.writeFileSync(mainPath, updatedContent);
}
copyAndUpdateSubLoFiles(subLoIndex: number, targets: string[]): void {
// Skip if this is sub-lo-1 and the directory exists
if (subLoIndex === 0 && this.doesSubLoDirectoryExist(1)) {
return;
}
const sourceDir = path.join(this.gamePath, 'configuration', 'variants-config', 'sub-lo-1');
const targetDir = path.join(this.gamePath, 'configuration', 'variants-config', `sub-lo-${subLoIndex + 1}`);
// Create target directory if it doesn't exist
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir, { recursive: true });
}
// Copy and update base config file
const baseConfigSource = path.join(sourceDir, `variantsBaseConfigSubLo1.ts`);
const baseConfigTarget = path.join(targetDir, `variantsBaseConfigSubLo${subLoIndex + 1}.ts`);
this.copyAndUpdateBaseConfig(baseConfigSource, baseConfigTarget, subLoIndex, targets);
// Copy and update variant files
const startVariant = subLoIndex * this.numberOfVariants + 1;
for (let i = 0; i < this.numberOfVariants; i++) {
const variantNumber = startVariant + i;
const sourceVariant = path.join(sourceDir, `${this.gameName}V${i + 1}.ts`);
const targetVariant = path.join(targetDir, `${this.gameName}V${variantNumber}.ts`);
this.copyAndUpdateVariantFile(sourceVariant, targetVariant, variantNumber, targets);
}
}
private copyAndUpdateBaseConfig(sourcePath: string, targetPath: string, subLoIndex: number, targets: string[]): void {
const content = fs.readFileSync(sourcePath, 'utf-8');
// Update the content with new sub-lo number and targets
let updatedContent = content
.replace(/SubLo1/g, `SubLo${subLoIndex + 1}`)
.replace(/sub-lo-1/g, `sub-lo-${subLoIndex + 1}`);
// Update targets in the config
const targetConfig = targets.map(target => ` ${target}: "${target}",`).join('\n');
updatedContent = updatedContent.replace(
/(\s+const config = {)[^}]+(\s+};)/s,
`$1\n${targetConfig}$2`
);
fs.writeFileSync(targetPath, updatedContent);
}
private copyAndUpdateVariantFile(sourcePath: string, targetPath: string, variantNumber: number, targets: string[]): void {
const content = fs.readFileSync(sourcePath, 'utf-8');
// Update the content with new variant number and targets
let updatedContent = content
.replace(/V1/g, `V${variantNumber}`)
.replace(/sub-lo-1/g, `sub-lo-${Math.floor((variantNumber - 1) / this.numberOfVariants) + 1}`);
// Update targets in the variant file
const targetConfig = targets.map(target => ` ${target}: "${target}",`).join('\n');
updatedContent = updatedContent.replace(
/(\s+const targets = {)[^}]+(\s+};)/s,
`$1\n${targetConfig}$2`
);
fs.writeFileSync(targetPath, updatedContent);
}
private generateUniqueId(): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < 8; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
private doesSubLoDirectoryExist(subLoIndex: number): boolean {
const subLoDir = path.join(this.gamePath, 'configuration', 'variants-config', `sub-lo-${subLoIndex}`);
return fs.existsSync(subLoDir);
}
}