UNPKG

dop-stick

Version:

Source control tooling for versionable-upgradeable smart contracts

264 lines 12.5 kB
"use strict"; 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 (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __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.ReviewAdapter = void 0; const readline_1 = __importDefault(require("readline")); const logger_1 = require("../core/logger"); const ethers = __importStar(require("ethers")); const box_1 = require("../core/box"); var DiamondCutAction; (function (DiamondCutAction) { DiamondCutAction[DiamondCutAction["ADD"] = 0] = "ADD"; DiamondCutAction[DiamondCutAction["REPLACE"] = 1] = "REPLACE"; DiamondCutAction[DiamondCutAction["REMOVE"] = 2] = "REMOVE"; })(DiamondCutAction || (DiamondCutAction = {})); class Terminal { static write(message) { process.stdout.write(message + '\n'); } static async prompt(question) { const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout }); try { return await new Promise(resolve => { rl.question(question, resolve); }); } finally { rl.close(); } } } class ReviewAdapter { constructor(mode) { this.mode = mode; } async processValidationResults(validatedModules) { const summary = this.prepareSummary(validatedModules); this.displaySummary(summary); if (this.mode === 'auto-pilot-beta') { logger_1.Logger.info('Auto-pilot mode: automatically accepting changes'); return true; } return await this.handleUserCommands(summary); } prepareSummary(modules) { const summary = { totalModules: modules.length, criticalIssues: 0, warnings: 0, suggestions: 0, invalidActions: 0, moduleResults: [] }; modules.forEach(module => { // Create module result const moduleResult = { moduleName: module.moduleName, missingFunctions: module.pendingMissingFunctions || [], collisions: Array.from(module.collisions.entries()) .filter(([_, hasCollision]) => hasCollision) .map(([selector]) => { // Find the signature for this selector const signature = Array.from(module.originalSignatures.keys()) .find(sig => ethers.utils.id(sig).slice(0, 10) === selector); return signature || selector; }), suggestedChanges: Array.from(module.suggestedChanges.entries()) .filter(([signature, suggestedAction]) => { // Only include changes where the suggested action is different const originalAction = module.originalSignatures.get(signature); return originalAction !== suggestedAction; }) .map(([signature, suggestedAction]) => ({ signature, from: module.originalSignatures.get(signature), to: suggestedAction })), invalidRemovals: module.pendingRemovals.map(r => r.signature), originalSignatures: module.originalSignatures }; summary.moduleResults.push(moduleResult); // Update summary counts summary.criticalIssues += moduleResult.missingFunctions.length; summary.warnings += moduleResult.collisions.length; summary.suggestions += moduleResult.suggestedChanges.length; // Now only counts actual changes summary.invalidActions += moduleResult.invalidRemovals.length; }); return summary; } displaySummary(summary) { Terminal.write('\n✨ VALIDATION REVIEW'); Terminal.write('────────────────'); summary.moduleResults.forEach((module, index) => { Terminal.write(`\n[${index + 1}/${summary.totalModules}] ${module.moduleName}`); // Display critical issues (missing functions) if any if (module.missingFunctions.length > 0) { Terminal.write(`🔴 ${module.missingFunctions.length} missing function${module.missingFunctions.length === 1 ? '' : 's'}`); } // Display invalid removals if any if (module.invalidRemovals.length > 0) { Terminal.write(`🟠 ${module.invalidRemovals.length} invalid removal${module.invalidRemovals.length === 1 ? '' : 's'}`); } // Display collisions if any if (module.collisions.length > 0) { Terminal.write(`🟡 ${module.collisions.length} selector collision${module.collisions.length === 1 ? '' : 's'}`); } // Display suggested changes if any - now in purple if (module.suggestedChanges.length > 0) { Terminal.write(`\x1b[35m↪ ${module.suggestedChanges.length} action change${module.suggestedChanges.length === 1 ? '' : 's'} suggested\x1b[0m`); } }); // Display summary totals Terminal.write('\nSUMMARY'); Terminal.write('───────'); const totalIssues = summary.criticalIssues + summary.warnings + summary.suggestions + summary.invalidActions; Terminal.write(`${totalIssues} issue${totalIssues === 1 ? '' : 's'} found across ${summary.totalModules} module${summary.totalModules === 1 ? '' : 's'}`); if (summary.criticalIssues > 0) { Terminal.write(`• ${summary.criticalIssues} critical issue${summary.criticalIssues === 1 ? '' : 's'} 🔴`); } if (summary.warnings > 0) { Terminal.write(`• ${summary.warnings} selector collision${summary.warnings === 1 ? '' : 's'} 🟡`); } if (summary.suggestions > 0) { Terminal.write(`\x1b[35m• ${summary.suggestions} action change${summary.suggestions === 1 ? '' : 's'} ↪\x1b[0m`); } if (summary.invalidActions > 0) { Terminal.write(`• ${summary.invalidActions} invalid removal${summary.invalidActions === 1 ? '' : 's'} 🟠`); } } async handleUserCommands(summary) { if (this.mode === 'strict' && (summary.criticalIssues > 0 || summary.invalidActions > 0)) { logger_1.Logger.error('Strict mode: Cannot proceed with critical issues or invalid actions'); return false; } while (true) { Terminal.write('\n\x1b[2mUse \'details <module>\' for more information'); Terminal.write('\'apply\' to accept all changes, \'exit\' to cancel\x1b[0m'); const command = await Terminal.prompt('\nEnter command (apply/details/exit): '); Terminal.write('\n'); if (command === 'apply') { const confirm = await Terminal.prompt('Are you sure you want to apply all changes? (y/N): '); if (confirm.toLowerCase() === 'y') { return true; } } else if (command === 'exit') { return false; } else if (command.startsWith('details ')) { const moduleName = command.substring(8); const found = this.displayModuleDetails(summary, moduleName); if (!found) { Terminal.write(`\nModule '${moduleName}' not found. Available modules:`); summary.moduleResults.forEach(m => Terminal.write(` • ${m.moduleName}`)); } } else { Terminal.write('\nAvailable commands:'); Terminal.write(' • details <module> - Show detailed module review'); Terminal.write(' • apply - Apply all suggested changes'); Terminal.write(' • exit - Cancel upgrade process'); } } } displayModuleDetails(summary, moduleName) { const moduleResult = summary.moduleResults.find(m => m.moduleName.toLowerCase() === moduleName.toLowerCase() || m.moduleName === moduleName); if (!moduleResult) { return false; } new box_1.Box(`${moduleResult.moduleName} Details`, { style: 'double', color: 'muted', padding: 1, margin: 0, align: 'left' }).render(); // Show module overview const totalFunctions = moduleResult.originalSignatures.size; Terminal.write(`\n\x1b[2m• ${totalFunctions} total function${totalFunctions === 1 ? '' : 's'}\x1b[0m`); // Show critical issues (missing functions) if (moduleResult.missingFunctions.length > 0) { Terminal.write('\n\x1b[31m🔴 MISSING FUNCTIONS\x1b[0m'); moduleResult.missingFunctions.forEach(fn => { Terminal.write(`• ${fn}`); Terminal.write(` \x1b[31m→ Function not found in contract\x1b[0m`); }); } // Show invalid removals if (moduleResult.invalidRemovals.length > 0) { Terminal.write('\n\x1b[33m🟠 INVALID REMOVALS\x1b[0m'); moduleResult.invalidRemovals.forEach(fn => { Terminal.write(`• ${fn}`); Terminal.write(` \x1b[33m→ Function does not exist onchain\x1b[0m`); }); } // Show collisions if (moduleResult.collisions.length > 0) { Terminal.write('\n\x1b[33m🟡 SELECTOR COLLISIONS\x1b[0m'); moduleResult.collisions.forEach(fn => { Terminal.write(`• ${fn}`); Terminal.write(` \x1b[33m→ Selector collision detected\x1b[0m`); }); } // Show suggested changes - now in purple if (moduleResult.suggestedChanges.length > 0) { Terminal.write('\n\x1b[35m↪ SUGGESTED ACTION CHANGES\x1b[0m'); moduleResult.suggestedChanges.forEach(change => { Terminal.write(`• ${change.signature}`); Terminal.write(` \x1b[35m→ Change ${this.getActionName(change.from)} to ${this.getActionName(change.to)}\x1b[0m`); }); } // Show unchanged functions const unchangedFunctions = Array.from(moduleResult.originalSignatures.entries()) .filter(([sig]) => !moduleResult.suggestedChanges.find(change => change.signature === sig)) .filter(([sig]) => !moduleResult.missingFunctions.includes(sig)) .filter(([sig]) => !moduleResult.invalidRemovals.includes(sig)); if (unchangedFunctions.length > 0) { Terminal.write('\n\x1b[32m✓ UNCHANGED FUNCTIONS\x1b[0m'); unchangedFunctions.forEach(([signature, action]) => { Terminal.write(`• ${signature}`); Terminal.write(` \x1b[32m→ ${this.getActionName(action)}\x1b[0m`); }); } return true; } getActionName(action) { switch (action) { case 0: return 'ADD'; case 1: return 'REPLACE'; case 2: return 'REMOVE'; default: return `UNKNOWN(${action})`; } } } exports.ReviewAdapter = ReviewAdapter; //# sourceMappingURL=reviewAdapter.js.map