Last active
May 10, 2024 13:51
-
-
Save bitsnaps/93397b65ac867fcfaf8b18760884d658 to your computer and use it in GitHub Desktop.
Find the most recent version of any given Node package by looking at every package.json file recursively in the current directory, I used this in order to detect the most recent version before downloading a new one instead of using `--prefer-offline` installation. It works offline.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/** | |
* This script finds the most recent installed version of any given Node package. | |
* Simple usage: | |
* node findRec.js vue [/path/to/projects] | |
*/ | |
const fs = require('fs'); | |
const os = require('os'); | |
const path = require('path'); | |
// Function to validate semver version strings | |
function isValidSemver(version) { | |
const semverRegex = /^\d+(\.\d+){0,2}$/; | |
return semverRegex.test(version); | |
} | |
// Function to recursively find package.json files | |
function findPackageJsons(dir, visited = new Set(), callback) { | |
if (typeof callback !== 'function') { | |
console.error('Callback must be a function'); | |
return; | |
} | |
try { | |
if (visited.has(dir)) { | |
return; // Skip if this directory has already been visited | |
} | |
visited.add(dir); // Mark this directory as visited | |
fs.readdirSync(dir).forEach(file => { | |
const filePath = path.join(dir, file); | |
const stat = fs.lstatSync(filePath); // Use lstat to get info about the link itself, not the target | |
if (stat.isSymbolicLink()) { | |
return; // Skip symbolic links to avoid loops | |
} | |
if (stat.isDirectory() && file !== 'node_modules') { | |
findPackageJsons(filePath, visited, callback); | |
} else if (file === 'package.json') { | |
callback(filePath); // Call the callback with the path to the package.json file | |
} | |
}); | |
} catch (err) { | |
if (err.code !== 'ENOENT') { | |
console.error(`Error reading directory ${dir}: ${err}`); | |
} | |
} | |
} | |
// Function to find the most recent version of a package | |
function findMostRecentVersion(currentDir, packageName, callback) { | |
let mostRecentVersion = null; | |
let directoryOfMostRecentVersion = null; // Store the directory of the most recent version | |
findPackageJsons(currentDir, new Set(), (packageJsonPath) => { | |
const packageJson = require(packageJsonPath); | |
const version = (packageJson.dependencies && packageJson.dependencies[packageName]) || | |
(packageJson.devDependencies && packageJson.devDependencies[packageName]); | |
if (version) { | |
const cleanVersion = cleanVersionString(version); | |
console.log(`mostRecent: ${mostRecentVersion}, v: ${cleanVersion}, at: ${path.dirname(packageJsonPath).replace(os.homedir(),'')}`); | |
if (cleanVersion && (!mostRecentVersion || compareVersions(cleanVersion, mostRecentVersion) > 0)) { | |
mostRecentVersion = cleanVersion; | |
directoryOfMostRecentVersion = path.dirname(packageJsonPath); // Update the directory storing the most recent version | |
} | |
} | |
}); | |
callback(mostRecentVersion, directoryOfMostRecentVersion); // Pass the directory along with the version to the callback | |
} | |
// Removes any range specifiers from the version string | |
function cleanVersionString(version) { | |
return version.replace(/^[^0-9]*/, ''); | |
} | |
// Compare two semantic version strings, return -1, 0, or 1 | |
function compareVersions(v1, v2) { | |
const parts1 = v1.split('.').map(Number); | |
const parts2 = v2.split('.').map(Number); | |
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { | |
const num1 = parts1[i] || 0; | |
const num2 = parts2[i] || 0; | |
if (num1 > num2) return 1; | |
if (num1 < num2) return -1; | |
} | |
return 0; | |
} | |
// Get package name from command line arguments | |
const packageName = process.argv[2]; | |
const currentDir = process.argv[3]?process.argv[3]:process.cwd(); | |
if (!packageName) { | |
console.error('Please provide a package name as an argument.'); | |
process.exit(1); | |
} | |
// Example usage | |
findMostRecentVersion(currentDir, packageName, (version, directory) => { | |
if (version) { | |
console.log(`The most recent version of ${packageName} found is ${version} in directory ${directory}`); | |
} else { | |
console.log(`Package ${packageName} not found in any package.json`); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment