update-modules
Version:
This module is used to update all modules in the project.
153 lines (124 loc) • 5.72 kB
JavaScript
require('colors');
const debug = process.argv?.pop() == '--debug';
const { SingleBar, Presets } = require('cli-progress');
const { exec } = require('node:child_process');
const { createInterface } = require('readline');
const dir = __dirname.split('node_modules')[0].replaceAll(`\\`, '/') + '/';
const package = require(dir + 'package.json');
const checkingUpdateBar = new SingleBar({
barCompleteChar: '●',
barIncompleteChar: '○',
fps: 1,
clearOnComplete: true,
hideCursor: true,
format: '▲ update-modules (controlling): '.green + '{bar} ({value} / {total})'.blue,
}, Presets.shades_grey);
const moduleInstallingBar = new SingleBar({
barCompleteChar: '●',
barIncompleteChar: '○',
fps: 1,
clearOnComplete: false,
hideCursor: true,
format: '▲ update-modules (installing): '.green + '{bar} ({value} / {total})'.blue,
}, Presets.shades_grey);
const ignored_modules = package?.updateModulesConfig?.ignore || [];
const dependencies = Object?.keys(package?.dependencies || []);
const devDependencies = Object?.keys(package?.devDependencies || []);
const normaly_modules = dependencies?.map(name => ({ name, version: package?.dependencies?.[name]?.replace('^', ''), dev: false }));
const dev_modules = devDependencies?.map(name => ({ name, version: package?.devDependencies?.[name]?.replace('^', ''), dev: true }));
const modules = [...normaly_modules, ...dev_modules];
/**
* Fetches the module data from the npm registry.
*
* @param {String} name This is the module name.
* @returns
*/
const fetchModule = async (name) => {
let output = null;
const addresses = [
'registry.npmjs.org/{name}',
'cdn.jsdelivr.net/npm/{name}@latest/package.json'
];
for (let address of addresses) {
try {
output = await fetch('https://' + address.replaceAll('{name}', name)).then(res => res?.json());
if (output) break;
} catch (error) {
if (debug) console.log('▲ update-modules: '.green + `Error: ${error}`.red);
}
}
return output;
}
(async () => {
checkingUpdateBar.start(modules?.length || 0, 0);
checkingUpdateBar.increment();
let updatebleModules = (await Promise.all(modules.map(async (module, i) => {
checkingUpdateBar.update(i + 1);
const data = await fetchModule(module.name);
if (!data) return null;
const newVersion = data?.['dist-tags']?.latest || data?.version;
if (!newVersion) return { ...module, latest: null };
const updateble = newVersion != module.version && !ignored_modules.includes(module.name);
if (updateble) return { ...module, latest: newVersion };
else return null;
}))).filter(f => f !== null);
checkingUpdateBar.stop();
if (updatebleModules.length == 0) return console.log('▲ update-modules: '.green + 'No updates available.'.green);
const nameLength = Math.max(...updatebleModules.map(module => module?.name?.length));
const versionLength = Math.max(...updatebleModules.map(module => module?.version?.length));
const notFoundModules = updatebleModules.filter(f => !f.latest);
if (notFoundModules.length > 0) {
console.log('▲ update-modules: '.green + `Please remove ${notFoundModules.length > 0 ? notFoundModules.map(m => `"${m?.name}"`).join(', ') : "None"} modules. Because the latest version could not be found.`.red);
return;
}
updatebleModules = updatebleModules.filter(f => f.latest);
const arrow = '─'.repeat(nameLength + versionLength + 20);
console.log(arrow.cyan);
console.log(`▲ ${'Module'.padEnd(nameLength)} ${'Version'.padEnd(versionLength)} Latest`.cyan);
for (let module of updatebleModules) {
var name = module.name + ' '.repeat(nameLength - module.name.length);
var version = module.version + ' '.repeat(versionLength - module.version.length);
console.log(`▲ ${name} : ${version} → ${module.latest}`.yellow);
}
console.log(arrow.cyan);
const client = createInterface({ input: process.stdin, output: process.stdout });
client.question('▲ update-modules: '.green + 'Do you want to update? (yes / no) \n'.blue + '> '.blue, async (answer) => {
const acceptAnswers = ['yes', 'y', 'true'];
if (!acceptAnswers.includes(answer.toLowerCase())) {
return client.close();
}
moduleInstallingBar.start(updatebleModules.length, 0);
moduleInstallingBar.increment();
for (let i = 0; i < updatebleModules.length; i++) {
moduleInstallingBar.update(i + 1);
const update = await moduleUpdate(updatebleModules[i].name, 'latest');
if (!update) {
console.log('▲ update-modules: '.green + `An error occurred while updating the "${updatebleModules[i].name}" module.`.red);
}
}
moduleInstallingBar.stop();
client.close();
});
client.on('close', () => {
process.exit();
});
})();
/**
* Updates the module.
*
* @param {String} name This is the module name.
* @param {String} verison This is the module version.
* @returns
*/
async function moduleUpdate(name, verison) {
return await new Promise((resolve, reject) => {
exec(`npm install ${name}@${verison}`, (error) => {
if (error) {
setTimeout(() => reject(error), 200)
} else {
setTimeout(() => resolve(true), 200)
}
});
});
}