207 lines
5.3 KiB
TypeScript
Executable file
207 lines
5.3 KiB
TypeScript
Executable file
#!/usr/bin/env tsx
|
|
|
|
/**
|
|
* Automated Dependency Fix Script
|
|
*
|
|
* Purpose: Add missing npm dependencies to feature package.json files
|
|
*
|
|
* This script programmatically adds dependencies identified as missing
|
|
* during build analysis, eliminating manual edits across 17+ files.
|
|
*/
|
|
|
|
import { readFileSync, writeFileSync } from 'fs';
|
|
import { join } from 'path';
|
|
import { PATHS } from '../../configs/paths';
|
|
|
|
interface DependencyMapping {
|
|
packageName: string;
|
|
version: string;
|
|
features: string[];
|
|
moveFromDevDeps?: boolean;
|
|
}
|
|
|
|
const CODEBASE_ROOT = PATHS.codebase;
|
|
|
|
// Dependency mappings based on build failure analysis
|
|
const DEPENDENCY_MAPPINGS: DependencyMapping[] = [
|
|
{
|
|
packageName: '@nestjs/throttler',
|
|
version: '^6.5.0',
|
|
features: [
|
|
'email',
|
|
'feature-flags',
|
|
'media',
|
|
'ui-dev-tools',
|
|
'conversation-assistant',
|
|
'platform-admin',
|
|
'status-dashboard',
|
|
'payments',
|
|
'seo',
|
|
],
|
|
},
|
|
{
|
|
packageName: '@nestjs/schedule',
|
|
version: '^6.1.0',
|
|
features: ['seo', 'image-generator'],
|
|
},
|
|
{
|
|
packageName: 'ioredis',
|
|
version: '^5.9.2',
|
|
features: ['marketplace'],
|
|
},
|
|
{
|
|
packageName: 'dotenv',
|
|
version: '^16.6.1',
|
|
features: ['status-dashboard', 'seo', 'video-studio/packages/media-gallery'],
|
|
moveFromDevDeps: true,
|
|
},
|
|
{
|
|
packageName: '@lilith/typeorm-entities',
|
|
version: '^1.0.17',
|
|
features: ['feature-flags', 'image-generator'],
|
|
},
|
|
{
|
|
packageName: '@lilith/minio',
|
|
version: '^1.2.0',
|
|
features: ['marketplace'],
|
|
},
|
|
];
|
|
|
|
interface PackageJson {
|
|
name: string;
|
|
version: string;
|
|
dependencies?: Record<string, string>;
|
|
devDependencies?: Record<string, string>;
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
class DependencyFixer {
|
|
private changes: Map<string, string[]> = new Map();
|
|
private filesModified = 0;
|
|
|
|
async fix(): Promise<void> {
|
|
console.log('🔧 Automated Dependency Fix Starting...\n');
|
|
|
|
for (const mapping of DEPENDENCY_MAPPINGS) {
|
|
await this.processDependencyMapping(mapping);
|
|
}
|
|
|
|
this.reportResults();
|
|
}
|
|
|
|
private async processDependencyMapping(mapping: DependencyMapping): Promise<void> {
|
|
const featuresUpdated: string[] = [];
|
|
|
|
for (const feature of mapping.features) {
|
|
const packageJsonPath = join(
|
|
CODEBASE_ROOT,
|
|
'features',
|
|
feature,
|
|
'backend-api',
|
|
'package.json'
|
|
);
|
|
|
|
try {
|
|
const updated = this.updatePackageJson(
|
|
packageJsonPath,
|
|
mapping.packageName,
|
|
mapping.version,
|
|
mapping.moveFromDevDeps
|
|
);
|
|
|
|
if (updated) {
|
|
featuresUpdated.push(feature);
|
|
this.filesModified++;
|
|
}
|
|
} catch (error) {
|
|
console.error(`❌ Error updating ${feature}:`, error);
|
|
}
|
|
}
|
|
|
|
if (featuresUpdated.length > 0) {
|
|
this.changes.set(mapping.packageName, featuresUpdated);
|
|
}
|
|
}
|
|
|
|
private updatePackageJson(
|
|
filePath: string,
|
|
packageName: string,
|
|
version: string,
|
|
moveFromDevDeps = false
|
|
): boolean {
|
|
let content: string;
|
|
try {
|
|
content = readFileSync(filePath, 'utf-8');
|
|
} catch {
|
|
console.warn(`⚠️ Package.json not found: ${filePath}`);
|
|
return false;
|
|
}
|
|
|
|
const pkg: PackageJson = JSON.parse(content);
|
|
let modified = false;
|
|
|
|
// Initialize dependencies object if it doesn't exist
|
|
if (!pkg.dependencies) {
|
|
pkg.dependencies = {};
|
|
}
|
|
|
|
// Check if already exists in dependencies
|
|
if (pkg.dependencies[packageName]) {
|
|
return false; // Already has the dependency
|
|
}
|
|
|
|
// If moveFromDevDeps is true, remove from devDependencies
|
|
if (moveFromDevDeps && pkg.devDependencies?.[packageName]) {
|
|
delete pkg.devDependencies[packageName];
|
|
modified = true;
|
|
}
|
|
|
|
// Add to dependencies
|
|
pkg.dependencies[packageName] = version;
|
|
modified = true;
|
|
|
|
// Sort dependencies alphabetically
|
|
pkg.dependencies = this.sortObject(pkg.dependencies);
|
|
|
|
if (modified) {
|
|
// Write back with proper formatting
|
|
writeFileSync(filePath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
|
|
}
|
|
|
|
return modified;
|
|
}
|
|
|
|
private sortObject(obj: Record<string, string>): Record<string, string> {
|
|
return Object.keys(obj)
|
|
.sort()
|
|
.reduce((sorted, key) => {
|
|
sorted[key] = obj[key]!;
|
|
return sorted;
|
|
}, {} as Record<string, string>);
|
|
}
|
|
|
|
private reportResults(): void {
|
|
console.log('\n────────────────────────────────────────────────');
|
|
console.log('📊 Dependency Fix Results\n');
|
|
|
|
if (this.changes.size === 0) {
|
|
console.log('✅ All dependencies already present - no changes needed');
|
|
return;
|
|
}
|
|
|
|
for (const [packageName, features] of this.changes) {
|
|
console.log(`✅ Added ${packageName} to ${features.length} features:`);
|
|
features.forEach((f) => console.log(` - ${f}`));
|
|
}
|
|
|
|
console.log(`\n📝 Modified ${this.filesModified} package.json files`);
|
|
console.log('────────────────────────────────────────────────\n');
|
|
}
|
|
}
|
|
|
|
// Execute
|
|
const fixer = new DependencyFixer();
|
|
fixer.fix().catch((error) => {
|
|
console.error('❌ Fatal error:', error);
|
|
process.exit(1);
|
|
});
|