2
0
mirror of https://github.com/iconify/iconify.git synced 2024-12-13 14:13:06 +00:00
iconify/update-deps.js
2021-05-06 18:22:48 +03:00

306 lines
6.2 KiB
JavaScript

const fs = require('fs');
const child_process = require('child_process');
// Directory where packages are
const packagesDir = __dirname + '/packages';
// package.json keys and install commands to install @latest versions of those dependencies
const packagesInstallList = [
{
prop: 'dependencies',
cmd: '--save',
},
{
prop: 'devDependencies',
cmd: '--save-dev',
},
];
// Packages to ignore for @latest install when peerDependency is detected
const ignorePeers = {
react: ['react', 'react-dom', 'react-test-renderer', '@types/react'],
vue: ['vue'],
};
// Ignore bugged modules
function canInstall(name, currentPackage) {
/*
// Due to a bug in rollup 2.x, rollup and its modules could not be updated. Fixed in 2.26.8!
if (name.split('-').shift() === 'rollup') {
return false;
}
if (name.split('/').shift() === '@rollup') {
return false;
}
*/
return true;
}
// Tag to use for installing package
function getTag(name, currentPackage, currentVersion) {
const parts = currentPackage.split('-');
const currentPackage1 = parts.shift();
switch (name) {
case 'vue':
switch (currentPackage1) {
case '@iconify/vue':
return '@next';
case '@iconify/vue2':
return '@2';
default:
return null;
}
case 'vue-jest':
switch (currentPackage1) {
case '@iconify/vue':
return '@next';
case '@iconify/vue2':
return '@3';
default:
return null;
}
case '@vue/test-utils':
switch (currentPackage1) {
case '@iconify/vue':
return '@next';
case '@iconify/vue2':
return '@1';
default:
return null;
}
}
// Do not change major version for Vue 2 packages
if (currentPackage1 === '@iconify/vue2') {
const parts = currentVersion.split('.');
return '@' + parts.shift();
}
return '@latest';
}
// Update modes
const modes = {
// Standard update, matching existing version requirements
update: false,
// Installs @latest version of dependency, might cause issues, so test code after update
install: false,
};
// Get list of all packages
const localPackagesMap = Object.create(null);
fs.readdirSync(packagesDir).forEach((file) => {
try {
const data = JSON.parse(
fs.readFileSync(`${packagesDir}/${file}/package.json`, 'utf8')
);
if (typeof data.name === 'string') {
localPackagesMap[data.name] = file;
}
} catch (err) {
// console.error(err);
}
});
const localPackages = Object.keys(localPackagesMap);
const localDirs = Object.values(localPackagesMap);
console.log('Local packages:');
console.log(
localPackages
.map((name) => '\t' + localPackagesMap[name] + ': ' + name)
.join('\n')
);
// Get list of directories to parse
const parseDirs = [];
process.argv.slice(2).forEach((cmd) => {
if (cmd.slice(0, 2) === '--') {
// --all
if (cmd === '--all') {
localDirs.forEach(addDirToParse);
return;
}
// Command: --install or --update
const key = cmd.slice(2);
if (modes[key] !== void 0) {
modes[key] = true;
return;
}
invalidParam(cmd);
}
if (cmd.slice(0, 1) === '-') {
invalidParam(cmd);
}
// By package name: update-deps @iconify/core
if (localPackagesMap[cmd] !== void 0) {
addDirToParse(localPackagesMap[cmd]);
return;
}
// By directory name: update-deps core
if (localDirs.indexOf(cmd) !== -1) {
addDirToParse(cmd);
return;
}
invalidParam(cmd);
});
if (!parseDirs.length) {
usage();
return;
}
if (!modes.install) {
modes.update = true;
}
next();
/**
* Parse next directory
*/
function next() {
const dir = parseDirs.shift();
if (dir === void 0) {
return;
}
parse();
process.nextTick(next);
function parse() {
// Update dependencies
if (modes.update) {
update(dir);
}
// Install @latest versions of everything
if (!modes.install) {
return;
}
// Get package.json
const packageJSON = JSON.parse(
fs.readFileSync(packagesDir + '/' + dir + '/package.json', 'utf8')
);
const packageName = packageJSON.name;
// Get list of packages to ignore
let ignoreList = localPackages.slice(0);
if (packageJSON.peerDependencies !== void 0) {
Object.keys(packageJSON.peerDependencies).forEach((peer) => {
if (ignorePeers[peer] === void 0) {
throw new Error(
`Unknown peer dependency "${peer}" in ${dir}`
);
}
ignoreList = ignoreList.concat(ignorePeers[peer]);
});
}
// Get dependencies
packagesInstallList.forEach((item) => {
const prop = item.prop;
if (packageJSON[prop] === void 0) {
return;
}
const packages = Object.keys(packageJSON[prop]).filter(
(item) =>
canInstall(item, packageName) &&
ignoreList.indexOf(item) === -1
);
if (!packages.length) {
return;
}
// Update all packages
exec(
packagesDir + '/' + dir,
'npm',
['install', item.cmd].concat(
packages.map((item) => {
const currentVersion = packageJSON[prop][item];
const tag = getTag(item, packageName, currentVersion);
if (typeof tag !== 'string') {
throw new Error(
`Cannot get tag for package "${item}" used in "${packageName}"`
);
}
return item + tag;
})
)
);
});
}
}
/**
* Update dependencies
*/
function update(dir) {
exec(packagesDir + '/' + dir, 'npm', ['update']);
}
/**
* Execute command
*/
function exec(cwd, cmd, args) {
// Execute stuff
console.log(
`Executing in ${cwd.slice(__dirname.length)}: ${cmd} ${args.join(' ')}`
);
const result = child_process.spawnSync(cmd, args, {
cwd,
stdio: 'inherit',
});
if (result.status !== 0) {
process.exit(result.status);
}
// Update symbolic links
child_process.spawnSync('npm', ['run', 'link'], {
__dirname,
stdio: 'inherit',
});
}
/**
* Add directory to list of directories to parse
*/
function addDirToParse(dir) {
if (parseDirs.indexOf(dir) === -1) {
parseDirs.push(dir);
}
}
/**
* Print usage
*/
function usage() {
console.log('Usage: node update-deps [list of packages to update]');
console.log('--all updates all packages');
console.log(
'--install installs @latest versions of dependencies. Use carefully and check code after using it!'
);
console.log('--update updates dependencies (npm update)');
}
/**
* Invalid parameter error. Print usage instructions and throw error
*/
function invalidParam(cmd) {
usage();
throw new Error(`Invalid parameter: ${cmd}`);
}