@diagramers/cli
Version:
Diagramers CLI - Command-line tools for managing Diagramers projects
275 lines • 12.4 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProjectUpdater = void 0;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const glob = __importStar(require("glob"));
const chalk_1 = __importDefault(require("chalk"));
const child_process_1 = require("child_process");
class ProjectUpdater {
constructor() {
this.currentProjectPath = process.cwd();
}
async update(options) {
// Check if we're in a valid project directory
if (!await this.isValidProject()) {
throw new Error('Not a valid project directory. Please run this command from your project root.');
}
// Create backup if requested
if (options.backup) {
await this.createBackup();
}
// Download latest template
console.log(chalk_1.default.blue('📦 Downloading latest template...'));
await this.downloadLatestTemplate();
// Get list of files that can be updated
const updateableFiles = await this.getUpdateableFiles();
// Check for conflicts
const conflicts = await this.checkConflicts(updateableFiles);
if (conflicts.length > 0 && !options.force) {
console.log(chalk_1.default.yellow('⚠️ Conflicts detected in the following files:'));
conflicts.forEach(file => console.log(chalk_1.default.yellow(` - ${file}`)));
console.log(chalk_1.default.yellow('Use --force to overwrite these files'));
throw new Error('Update aborted due to conflicts');
}
// Perform the update
await this.performUpdate(updateableFiles, options.force || false);
// Clean up temporary files
await this.cleanup();
console.log(chalk_1.default.green('✅ Project updated successfully!'));
}
async isValidProject() {
const packageJsonPath = path.join(this.currentProjectPath, 'package.json');
// Check for package.json and diagramers project structure
const hasPackageJson = await fs.pathExists(packageJsonPath);
if (!hasPackageJson) {
return false;
}
// Check if it's a diagramers project
try {
const packageJson = await fs.readJson(packageJsonPath);
const hasApiStructure = await fs.pathExists(path.join(this.currentProjectPath, 'src', 'modules')) &&
await fs.pathExists(path.join(this.currentProjectPath, 'src', 'core')) &&
await fs.pathExists(path.join(this.currentProjectPath, 'src', 'shared'));
return hasApiStructure ||
(packageJson.name && packageJson.name.includes('diagramers')) ||
(packageJson.description && packageJson.description.includes('diagramers')) ||
(packageJson.description && packageJson.description.includes('API project'));
}
catch (error) {
return false;
}
}
async createBackup() {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupPath = path.join(this.currentProjectPath, `backup-${timestamp}`);
await fs.copy(this.currentProjectPath, backupPath, {
filter: (src) => {
const relativePath = path.relative(this.currentProjectPath, src);
return !relativePath.startsWith('node_modules') &&
!relativePath.startsWith('.git') &&
!relativePath.startsWith('backup-') &&
!relativePath.startsWith('temp-update-');
}
});
console.log(chalk_1.default.blue(`📦 Backup created at: ${backupPath}`));
}
async downloadLatestTemplate() {
const tempDir = path.join(this.currentProjectPath, 'temp-update-download');
try {
// Create temporary directory
await fs.ensureDir(tempDir);
// Create temporary package.json
const tempPackageJson = {
name: 'temp-update',
version: '1.0.0',
private: true
};
await fs.writeJson(path.join(tempDir, 'package.json'), tempPackageJson, { spaces: 2 });
// Install the latest API template
console.log(chalk_1.default.blue(' Installing @diagramers/api...'));
(0, child_process_1.execSync)('npm install @diagramers/api --no-save', {
cwd: tempDir,
stdio: 'inherit'
});
}
catch (error) {
throw new Error(`Failed to download template: ${error.message}`);
}
}
async getUpdateableFiles() {
// Files that can be safely updated from the template
const updateableFiles = [
'src/core/app.ts',
'src/core/config/index.ts',
'src/core/config/interfaces.ts',
'src/core/database/connection.ts',
'src/core/database/seeder.ts',
'src/core/logging/index.ts',
'src/core/middleware/certificate-middleware.ts',
'src/core/server/manager.ts',
'src/core/utils/',
'src/shared/constants/enums.ts',
'src/shared/helpers/',
'src/shared/types/base-entity.ts',
'src/shared/types/common.ts',
'src/shared/types/database-adapter.ts',
'src/shared/types/result.ts',
'src/shared/utils/handle-response.ts',
'src/shared/utils/mongodb-adapter.ts',
'src/plugins/base/',
'src/plugins/registry/',
'webpack.config.js',
'tsconfig.json',
'.env.example'
];
const existingFiles = [];
for (const file of updateableFiles) {
const fullPath = path.join(this.currentProjectPath, file);
if (await fs.pathExists(fullPath)) {
const stat = await fs.stat(fullPath);
if (stat.isDirectory()) {
// Add all files in the directory
const files = glob.sync('**/*', { cwd: fullPath, nodir: true });
existingFiles.push(...files.map(f => path.join(file, f)));
}
else {
existingFiles.push(file);
}
}
}
return existingFiles;
}
async checkConflicts(files) {
const conflicts = [];
const tempDir = path.join(this.currentProjectPath, 'temp-update-download');
const templatePath = path.join(tempDir, 'node_modules', '@diagramers', 'api');
for (const file of files) {
const projectPath = path.join(this.currentProjectPath, file);
const templateFilePath = path.join(templatePath, file);
if (await fs.pathExists(projectPath) && await fs.pathExists(templateFilePath)) {
try {
const projectContent = await fs.readFile(projectPath, 'utf8');
const templateContent = await fs.readFile(templateFilePath, 'utf8');
// Simple content comparison - in a real implementation, you'd use a more sophisticated diff
if (projectContent !== templateContent) {
conflicts.push(file);
}
}
catch (error) {
// If we can't read the files, consider it a conflict
conflicts.push(file);
}
}
}
return conflicts;
}
async performUpdate(files, force) {
console.log(chalk_1.default.blue('📝 Updating project files...'));
const tempDir = path.join(this.currentProjectPath, 'temp-update-download');
const templatePath = path.join(tempDir, 'node_modules', '@diagramers', 'api');
let updatedCount = 0;
for (const file of files) {
const projectPath = path.join(this.currentProjectPath, file);
const templateFilePath = path.join(templatePath, file);
if (await fs.pathExists(templateFilePath)) {
try {
// Copy file from template to project
await fs.copy(templateFilePath, projectPath);
console.log(chalk_1.default.green(`✅ Updated: ${file}`));
updatedCount++;
}
catch (error) {
console.log(chalk_1.default.yellow(`⚠️ Could not update: ${file}`));
}
}
}
console.log(chalk_1.default.blue(`📊 Updated ${updatedCount} files`));
// Update package.json dependencies
await this.updatePackageJson(templatePath);
}
async updatePackageJson(templatePath) {
try {
const projectPackageJsonPath = path.join(this.currentProjectPath, 'package.json');
const templatePackageJsonPath = path.join(templatePath, 'package.json');
if (await fs.pathExists(templatePackageJsonPath)) {
const projectPackageJson = await fs.readJson(projectPackageJsonPath);
const templatePackageJson = await fs.readJson(templatePackageJsonPath);
// Update dependencies and devDependencies
if (templatePackageJson.dependencies) {
projectPackageJson.dependencies = {
...projectPackageJson.dependencies,
...templatePackageJson.dependencies
};
}
if (templatePackageJson.devDependencies) {
projectPackageJson.devDependencies = {
...projectPackageJson.devDependencies,
...templatePackageJson.devDependencies
};
}
// Update scripts
if (templatePackageJson.scripts) {
projectPackageJson.scripts = {
...projectPackageJson.scripts,
...templatePackageJson.scripts
};
}
await fs.writeJson(projectPackageJsonPath, projectPackageJson, { spaces: 2 });
console.log(chalk_1.default.green('✅ Updated package.json'));
}
}
catch (error) {
console.log(chalk_1.default.yellow('⚠️ Could not update package.json'));
}
}
async cleanup() {
const tempDir = path.join(this.currentProjectPath, 'temp-update-download');
try {
if (await fs.pathExists(tempDir)) {
await fs.remove(tempDir);
}
}
catch (error) {
console.log(chalk_1.default.yellow('⚠️ Could not clean up temporary files'));
}
}
}
exports.ProjectUpdater = ProjectUpdater;
//# sourceMappingURL=project-updater.js.map