UNPKG

@boilerbuilder/deps-analyzer

Version:

CLI tool to analyze dependency evolution and release frequency

119 lines (94 loc) 4.03 kB
// ============================================================================ // LIBYEAR-LIKE DRIFT/PULSE CALCULATIONS (based on libyear LGPL-3.0) // ============================================================================ const cleanVersion = require('../utils/cleanVersion'); const findMaxAllowedVersion = require('../utils/findMaxAllowedVersion'); const DAYS_IN_YEAR = 365.2425; /** * Calculate drift (time since current version vs latest version) * @param {string} currentVersionDate - ISO date string of current version * @param {string} latestVersionDate - ISO date string of latest version * @returns {number} Drift in years */ function calculateDrift(currentVersionDate, latestVersionDate) { if (!currentVersionDate || !latestVersionDate) return 0; try { const currentDate = new Date(currentVersionDate); const latestDate = new Date(latestVersionDate); if (isNaN(currentDate.getTime()) || isNaN(latestDate.getTime())) return 0; const diffMs = latestDate.getTime() - currentDate.getTime(); const diffDays = diffMs / (1000 * 60 * 60 * 24); return Math.max(0, diffDays / DAYS_IN_YEAR); } catch (error) { return 0; } } /** * Calculate pulse (time since latest version was released) * @param {string} latestVersionDate - ISO date string of latest version * @returns {number} Pulse in years */ function calculatePulse(latestVersionDate) { if (!latestVersionDate) return 0; try { const latestDate = new Date(latestVersionDate); const now = new Date(); if (isNaN(latestDate.getTime())) return 0; const diffMs = now.getTime() - latestDate.getTime(); const diffDays = diffMs / (1000 * 60 * 60 * 24); return Math.max(0, diffDays / DAYS_IN_YEAR); } catch (error) { return 0; } } /** * Calculate drift and pulse for a dependency based on npm data and current version * @param {Object} npmData - NPM package data with time field * @param {string} currentVersion - Current version used in package.json * @param {string} maxVersion - Optional maximum version constraint from max-deps.json only * @returns {Object} Object with drift and pulse values, or error */ function calculateDependencyDriftPulse(npmData, currentVersion, maxVersion = null) { if (!npmData || !npmData.time || !currentVersion) { return { drift: 0, pulse: 0, error: 'Missing data' }; } const cleanCurrent = cleanVersion(currentVersion); const currentVersionDate = npmData.time[cleanCurrent]; if (!currentVersionDate) { return { drift: 0, pulse: 0, error: `Version ${currentVersion} not found` }; } // DRIFT: Always calculate based on latest version (shows real technical debt) let driftTargetVersion = npmData.latestVersion; let driftTargetDate = npmData.time[driftTargetVersion]; if (!driftTargetDate) { return { drift: 0, pulse: 0, error: `Latest version ${driftTargetVersion} not found` }; } // PULSE: Use constrained version if max-deps.json explicitly sets it, otherwise latest let pulseTargetVersion = driftTargetVersion; // Default to latest let pulseTargetDate = driftTargetDate; let constrainedByMaxVersion = false; // Only apply max-deps.json constraints (not package.json constraints like ^20) if (maxVersion) { const availableVersions = Object.keys(npmData.time).filter(v => v !== 'created' && v !== 'modified'); const maxAllowedVersion = findMaxAllowedVersion(maxVersion, availableVersions); if (maxAllowedVersion && npmData.time[maxAllowedVersion]) { pulseTargetVersion = maxAllowedVersion; pulseTargetDate = npmData.time[maxAllowedVersion]; constrainedByMaxVersion = true; } } const drift = calculateDrift(currentVersionDate, driftTargetDate); const pulse = calculatePulse(pulseTargetDate); return { drift, pulse, targetVersion: pulseTargetVersion, constrainedByMaxVersion }; } module.exports = { calculateDrift, calculatePulse, calculateDependencyDriftPulse, DAYS_IN_YEAR };