UNPKG

depsweep

Version:

🌱 Automated intelligent dependency cleanup with environmental impact reporting

246 lines (245 loc) • 11.6 kB
import { ENVIRONMENTAL_CONSTANTS } from "./constants.js"; export function detectUserRegion() { try { const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; if (timezone.includes("America/") || timezone.includes("US/") || timezone.includes("Canada/")) { return "NA"; } else if (timezone.includes("Europe/") || timezone.includes("Africa/")) { return "EU"; } else if (timezone.includes("Asia/") || timezone.includes("Australia/") || timezone.includes("Pacific/")) { return "AP"; } return "GLOBAL"; } catch (error) { return "NA"; } } export function getRegionalCarbonIntensity(region) { switch (region) { case "NA": return ENVIRONMENTAL_CONSTANTS.CARBON_INTENSITY_NA; case "EU": return ENVIRONMENTAL_CONSTANTS.CARBON_INTENSITY_EU; case "AP": return ENVIRONMENTAL_CONSTANTS.CARBON_INTENSITY_AP; default: return ENVIRONMENTAL_CONSTANTS.CARBON_INTENSITY; } } export function getTimeOfDayMultiplier() { try { const hour = new Date().getHours(); const isWeekend = new Date().getDay() === 0 || new Date().getDay() === 6; const isPeakHour = (hour >= 6 && hour < 10) || (hour >= 18 && hour < 22); if (isWeekend) { return ENVIRONMENTAL_CONSTANTS.OFF_PEAK_ENERGY_MULTIPLIER; } else if (isPeakHour) { return ENVIRONMENTAL_CONSTANTS.PEAK_ENERGY_MULTIPLIER; } else { return ENVIRONMENTAL_CONSTANTS.OFF_PEAK_ENERGY_MULTIPLIER; } } catch (error) { console.log("DEBUG: getTimeOfDayMultiplier error, defaulting to 1.0:", error); return 1.0; } } export function calculateCPUEnergy(diskSpaceGB, processingComplexity = 1.0) { const baseEnergy = diskSpaceGB * ENVIRONMENTAL_CONSTANTS.CPU_ENERGY_PER_GB; const complexityMultiplier = Math.max(0.5, Math.min(2.0, processingComplexity)); return Math.max(0, baseEnergy * complexityMultiplier); } export function calculateMemoryEnergy(diskSpaceGB, accessFrequency = 1.0) { const baseEnergy = diskSpaceGB * ENVIRONMENTAL_CONSTANTS.MEMORY_ENERGY_PER_GB; const frequencyMultiplier = Math.max(0.1, Math.min(3.0, accessFrequency)); return Math.max(0, baseEnergy * frequencyMultiplier); } export function calculateLatencyEnergy(diskSpaceMB, averageLatency = 50) { const baseEnergy = diskSpaceMB * ENVIRONMENTAL_CONSTANTS.LATENCY_ENERGY_PER_MB; const latencyMultiplier = Math.max(0.5, Math.min(2.0, averageLatency / 50)); return Math.max(0, baseEnergy * latencyMultiplier); } export function calculateBuildEnergy(installTimeHours, buildComplexity = 1.0) { const baseEnergy = installTimeHours * ENVIRONMENTAL_CONSTANTS.BUILD_SYSTEM_ENERGY_PER_HOUR; const complexityMultiplier = Math.max(0.5, Math.min(2.5, buildComplexity)); return Math.max(0, baseEnergy * complexityMultiplier); } export function calculateCICDEnergy(monthlyDownloads, buildFrequency = 1.0) { if (!monthlyDownloads || monthlyDownloads <= 0) return 0; const dailyBuilds = Math.max(1, monthlyDownloads / 30); const baseEnergy = dailyBuilds * ENVIRONMENTAL_CONSTANTS.CI_CD_ENERGY_PER_BUILD; const frequencyMultiplier = Math.max(0.5, Math.min(2.0, buildFrequency)); return Math.max(0, baseEnergy * frequencyMultiplier); } export function calculateRegistryEnergy(monthlyDownloads) { if (!monthlyDownloads || monthlyDownloads <= 0) return 0; return Math.max(0, monthlyDownloads * ENVIRONMENTAL_CONSTANTS.REGISTRY_ENERGY_PER_DOWNLOAD); } export function calculateLifecycleEnergy(totalEnergy) { return Math.max(0, totalEnergy * (ENVIRONMENTAL_CONSTANTS.LIFECYCLE_ENERGY_MULTIPLIER - 1)); } export function calculateRenewableEnergyBreakdown(totalEnergy) { const renewablePercentage = ENVIRONMENTAL_CONSTANTS.RENEWABLE_ENERGY_PERCENTAGE; const renewable = totalEnergy * renewablePercentage; const fossil = totalEnergy * (1 - renewablePercentage); return { renewable, fossil, percentage: renewablePercentage * 100, }; } export function calculateFinancialValue(carbonSavings, waterSavings) { const carbonOffsetValue = carbonSavings * ENVIRONMENTAL_CONSTANTS.CARBON_OFFSET_COST_PER_KG; const waterTreatmentValue = waterSavings * ENVIRONMENTAL_CONSTANTS.WATER_TREATMENT_COST_PER_LITER; const totalValue = carbonOffsetValue + waterTreatmentValue; return { carbonOffsetValue, waterTreatmentValue, totalValue, }; } export function calculateEwasteReduction(diskSpaceGB) { return Math.max(0, diskSpaceGB * ENVIRONMENTAL_CONSTANTS.EWASTE_IMPACT_PER_GB); } export function calculateServerUtilizationImprovement(diskSpaceGB) { const baseImprovement = ENVIRONMENTAL_CONSTANTS.SERVER_UTILIZATION_IMPROVEMENT; const sizeMultiplier = Math.max(0.5, Math.min(2.0, diskSpaceGB / 10)); return Math.max(0, baseImprovement * sizeMultiplier); } export function calculateDeveloperProductivityGain(installTimeHours, teamSize = 1) { const baseGain = installTimeHours * ENVIRONMENTAL_CONSTANTS.BUILD_TIME_PRODUCTIVITY_GAIN; const teamMultiplier = Math.max(1, teamSize); return Math.max(0, baseGain * teamMultiplier); } export function calculateBuildTimeReduction(installTimeSeconds) { const efficiencyGain = ENVIRONMENTAL_CONSTANTS.EFFICIENCY_IMPROVEMENT / 100; return Math.max(0, installTimeSeconds * efficiencyGain); } export function calculateComprehensiveEnvironmentalImpact(diskSpace, installTime, monthlyDownloads, options = {}) { const region = options.region || detectUserRegion(); const carbonIntensity = getRegionalCarbonIntensity(region); const timeOfDayMultiplier = getTimeOfDayMultiplier(); console.log("DEBUG: calculateComprehensiveEnvironmentalImpact region:", region); console.log("DEBUG: calculateComprehensiveEnvironmentalImpact carbonIntensity:", carbonIntensity); console.log("DEBUG: calculateComprehensiveEnvironmentalImpact timeOfDayMultiplier:", timeOfDayMultiplier); const diskSpaceGB = Math.max(0, diskSpace / (1024 * 1024 * 1024)); const diskSpaceMB = Math.max(0, diskSpace / (1024 * 1024)); const installTimeHours = Math.max(0, installTime / 3600); const transferEnergy = diskSpaceGB * ENVIRONMENTAL_CONSTANTS.ENERGY_PER_GB; const networkEnergy = diskSpaceMB * ENVIRONMENTAL_CONSTANTS.NETWORK_ENERGY_PER_MB; const storageEnergy = (diskSpaceGB * ENVIRONMENTAL_CONSTANTS.STORAGE_ENERGY_PER_GB_YEAR) / 12; const cpuEnergy = calculateCPUEnergy(diskSpaceGB, options.processingComplexity); const memoryEnergy = calculateMemoryEnergy(diskSpaceGB, options.accessFrequency); const latencyEnergy = calculateLatencyEnergy(diskSpaceMB, options.averageLatency); const buildEnergy = calculateBuildEnergy(installTimeHours, options.buildComplexity); const ciCdEnergy = calculateCICDEnergy(monthlyDownloads, options.buildFrequency); const registryEnergy = calculateRegistryEnergy(monthlyDownloads); const baseEnergySavings = transferEnergy + networkEnergy + storageEnergy + cpuEnergy + memoryEnergy + latencyEnergy + buildEnergy + ciCdEnergy + registryEnergy; const lifecycleEnergy = calculateLifecycleEnergy(baseEnergySavings); const totalEnergySavings = baseEnergySavings + lifecycleEnergy; const peakEnergySavings = totalEnergySavings * timeOfDayMultiplier; const offPeakEnergySavings = totalEnergySavings * ENVIRONMENTAL_CONSTANTS.OFF_PEAK_ENERGY_MULTIPLIER; const carbonSavings = Math.max(0, totalEnergySavings * carbonIntensity); const waterSavings = Math.max(0, totalEnergySavings * ENVIRONMENTAL_CONSTANTS.WATER_PER_KWH); const treesEquivalent = Math.max(0, carbonSavings * ENVIRONMENTAL_CONSTANTS.TREES_PER_KG_CO2); const carMilesEquivalent = Math.max(0, carbonSavings / ENVIRONMENTAL_CONSTANTS.CO2_PER_CAR_MILE); const renewableBreakdown = calculateRenewableEnergyBreakdown(totalEnergySavings); const financialValue = calculateFinancialValue(carbonSavings, waterSavings); const ewasteReduction = calculateEwasteReduction(diskSpaceGB); const serverUtilizationImprovement = calculateServerUtilizationImprovement(diskSpaceGB); const developerProductivityGain = calculateDeveloperProductivityGain(installTimeHours, options.teamSize); const buildTimeReduction = calculateBuildTimeReduction(installTime); const efficiencyGain = Math.min(50, ENVIRONMENTAL_CONSTANTS.EFFICIENCY_IMPROVEMENT); return { carbonSavings, energySavings: totalEnergySavings, waterSavings, treesEquivalent, carMilesEquivalent, efficiencyGain, networkSavings: networkEnergy, storageSavings: storageEnergy, transferEnergy, cpuEnergy, memoryEnergy, latencyEnergy, buildEnergy, ciCdEnergy, registryEnergy, lifecycleEnergy, carbonOffsetValue: financialValue.carbonOffsetValue, waterTreatmentValue: financialValue.waterTreatmentValue, totalFinancialValue: financialValue.totalValue, carbonIntensityUsed: carbonIntensity, regionalMultiplier: region === "GLOBAL" ? 1.0 : 1.1, peakEnergySavings, offPeakEnergySavings, timeOfDayMultiplier, renewableEnergySavings: renewableBreakdown.renewable, fossilFuelSavings: renewableBreakdown.fossil, renewablePercentage: renewableBreakdown.percentage, ewasteReduction, serverUtilizationImprovement, developerProductivityGain, buildTimeReduction, }; } export function validateEnvironmentalCalculations(impact) { const warnings = []; const errors = []; if (impact.carbonSavings < 0) errors.push("Carbon savings cannot be negative"); if (impact.energySavings < 0) errors.push("Energy savings cannot be negative"); if (impact.waterSavings < 0) errors.push("Water savings cannot be negative"); if (impact.carbonSavings > 10000) warnings.push("Carbon savings seems unusually high"); if (impact.energySavings > 50000) warnings.push("Energy savings seems unusually high"); if (impact.treesEquivalent > 1000) warnings.push("Tree equivalent seems unusually high"); const expectedCarbon = impact.energySavings * impact.carbonIntensityUsed; const carbonDifference = Math.abs(impact.carbonSavings - expectedCarbon); if (carbonDifference > 0.01) { warnings.push(`Carbon calculation inconsistency: ${carbonDifference.toFixed(3)} kg CO2e difference`); } if (impact.renewablePercentage < 0 || impact.renewablePercentage > 100) { errors.push("Renewable energy percentage must be between 0 and 100"); } return { isValid: errors.length === 0, warnings, errors, }; } export function formatEnvironmentalImpact(impact) { return { carbonSavings: `${impact.carbonSavings.toFixed(3)} kg CO2e`, energySavings: `${impact.energySavings.toFixed(2)} kWh`, waterSavings: `${impact.waterSavings.toFixed(1)} L`, treesEquivalent: `${impact.treesEquivalent.toFixed(2)} trees`, carMilesEquivalent: `${impact.carMilesEquivalent.toFixed(1)} miles`, financialValue: `$${impact.totalFinancialValue.toFixed(2)}`, renewablePercentage: `${impact.renewablePercentage.toFixed(1)}%`, }; }