@pierrad/web-carbon-analyzer
Version:
A tool to measure the carbon footprint of websites using CO2.js
177 lines • 6.97 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Output Formatter module
* Formats calculation results into structured output
*/
const logger_1 = __importDefault(require("../utils/logger"));
const default_1 = __importDefault(require("../config/default"));
class OutputFormatter {
constructor(customConfig = {}) {
this.config = { ...default_1.default.output, ...customConfig };
}
/**
* Format calculation results as a structured object
* @param {string} url - The URL that was analyzed
* @param {ResourcesData} resourcesData - Resource data from the NetworkInterceptor
* @param {EmissionsData} emissionsData - Emissions data from the CO2Calculator
* @param {Object} metadata - Additional metadata about the analysis
* @returns {FormattedResults} - Formatted results
*/
formatResults(url, resourcesData, emissionsData, metadata = {}) {
logger_1.default.info('Formatting output results');
// Create metadata section
const formattedResults = {
metadata: {
url,
timestamp: new Date().toISOString(),
duration: resourcesData.totalDuration,
configuration: metadata.configuration || {},
...metadata
},
// Create summary section
summary: {
totalEmissions: this.roundNumber(emissionsData.totalEmissions),
totalSize: resourcesData.totalSize,
totalRequests: resourcesData.totalResources,
percentageGreen: this.calculateGreenPercentage(emissionsData),
comparisons: this.formatComparisons(emissionsData.comparisons)
},
// Create breakdowns section
breakdowns: {
byType: this.formatTypeBreakdown(emissionsData.byType),
byDomain: this.formatDomainBreakdown(emissionsData.byDomain),
byHosting: this.formatHostingBreakdown(emissionsData.byGreenHosting)
}
};
// Add detailed resources if configured
if (this.config.includeResourceDetails) {
formattedResults.resources = this.formatResourceDetails(emissionsData.perResource);
}
logger_1.default.info('Output formatting completed');
return formattedResults;
}
/**
* Calculate the percentage of green-hosted resources
* @param {EmissionsData} emissionsData - Emissions data
* @returns {number} - Percentage of green-hosted resources (by size)
*/
calculateGreenPercentage(emissionsData) {
const green = emissionsData.byGreenHosting.green.size || 0;
const nonGreen = emissionsData.byGreenHosting.nonGreen.size || 0;
const unknown = emissionsData.byGreenHosting.unknown.size || 0;
const total = green + nonGreen + unknown;
if (total === 0) {
return 0;
}
return this.roundNumber((green / total) * 100);
}
/**
* Format the resource type breakdown
* @param {Record<string, TypeEmissions>} typeData - Breakdown by resource type
* @returns {Record<string, TypeEmissions>} - Formatted breakdown
*/
formatTypeBreakdown(typeData) {
const result = {};
for (const [type, data] of Object.entries(typeData)) {
result[type] = {
size: data.size,
emissions: this.roundNumber(data.emissions),
count: data.count
};
}
return result;
}
/**
* Format the domain breakdown
* @param {Record<string, DomainEmissions>} domainData - Breakdown by domain
* @returns {Record<string, DomainEmissions>} - Formatted breakdown
*/
formatDomainBreakdown(domainData) {
const result = {};
for (const [domain, data] of Object.entries(domainData)) {
result[domain] = {
size: data.size,
emissions: this.roundNumber(data.emissions),
count: data.count,
isGreen: data.isGreen
};
}
return result;
}
/**
* Format the green hosting breakdown
* @param {Object} hostingData - Breakdown by hosting type
* @returns {Object} - Formatted breakdown
*/
formatHostingBreakdown(hostingData) {
return {
green: {
size: hostingData.green.size,
emissions: this.roundNumber(hostingData.green.emissions),
count: hostingData.green.count
},
nonGreen: {
size: hostingData.nonGreen.size,
emissions: this.roundNumber(hostingData.nonGreen.emissions),
count: hostingData.nonGreen.count
},
unknown: {
size: hostingData.unknown.size,
emissions: this.roundNumber(hostingData.unknown.emissions),
count: hostingData.unknown.count
}
};
}
/**
* Format the detailed resource list
* @param {ResourceEmissions[]} resourcesData - List of resource emissions data
* @returns {ResourceEmissions[]} - Formatted resource list
*/
formatResourceDetails(resourcesData) {
return resourcesData.map(resource => ({
...resource,
emissions: this.roundNumber(resource.emissions)
}));
}
/**
* Format the human-readable comparisons
* @param {Comparisons} comparisons - Comparison metrics
* @returns {Comparisons} - Formatted comparisons
*/
formatComparisons(comparisons) {
return {
treeSeconds: this.roundNumber(comparisons.treeSeconds),
carMeters: this.roundNumber(comparisons.carMeters),
smartphoneCharges: this.roundNumber(comparisons.smartphoneCharges),
waterBoiledML: this.roundNumber(comparisons.waterBoiledML)
};
}
/**
* Round a number to a reasonable precision
* @param {number} value - The number to round
* @param {number} decimals - Number of decimal places
* @returns {number} - Rounded number
*/
roundNumber(value, decimals = 4) {
const factor = Math.pow(10, decimals);
return Math.round(value * factor) / factor;
}
/**
* Convert results to a string format
* @param {FormattedResults} results - Formatted results object
* @returns {string} - String representation of results
*/
stringify(results) {
if (this.config.format === 'json') {
return JSON.stringify(results, null, 2);
}
// Support for other formats like CSV could be added here
return JSON.stringify(results);
}
}
exports.default = OutputFormatter;
//# sourceMappingURL=output-formatter.js.map