depsweep
Version:
🌱 Automated intelligent dependency cleanup with environmental impact reporting
246 lines (245 loc) • 11.6 kB
JavaScript
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)}%`,
};
}