npm-consider
Version:
Check npm package dependencies, stats and impact on your package before installing it
192 lines (183 loc) • 4.74 kB
JavaScript
/**
* @file install action
*/
const getLocalPackage = require('./getLocalPackage');
const colors = require('colors/safe');
const walkDependencies = require('./walkDependencies');
const getInstallCommand = require('./getInstallCommand');
const inquirer = require('inquirer');
const exec = require('./exec');
const showDetails = require('./showDetails');
const isProduction = require('./isProduction');
const getPackagesStats = require('./getPackagesStats');
const formatLicenseType = require('./formatLicenseType');
const filesize = require('filesize');
const getSimpleTable = require('./getSimpleTable');
const program = require('commander');
const readline = require('readline');
const printError = require('./printError');
/**
* indicates if any limits of test config are not satisfied
* @type {Boolean}
*/
let testFailed = false;
/**
* @return {Promise}
*/
function promptAction(packages) {
return getInstallCommand().then(({ command, args }) => {
const choices = [
`Install (${
colors.bold(`${
command
}${
args.length ? ' ' : ''
}${
args.join(` `)
}`)
})`,
`Details`,
`Skip`
];
return inquirer.prompt({
type: `list`,
name: `next`,
message: `What is next?`,
choices
}).then(({ next }) => {
switch (choices.indexOf(next)) {
case 0:
exec(command, args);
return Promise.reject();
case 1:
return showDetails(packages);
default:
process.exit(0);
}
}).catch((e) => {
if (e) {
throw e;
}
});
});
}
/**
* @param {object} localPackage package.json
* @return {object} test config
*/
function getTestConfig(localPackage) {
const config = localPackage.config || {};
return config;
}
/**
* @param {number} current
* @param {number} max
* @param {function} [formatter=String]
* @return {string}
*/
function getLimitResult(current, max, formatter = String) {
if (!max) {
return '';
}
if (current < max) {
return colors.green(`<= ${formatter(max)}`);
}
testFailed = true;
return colors.red(`> ${formatter(max)}`);
}
/**
* @param {string[]} allowedLicenseTypes
* @param {string} type
* @return {string}
*/
function checkLicenseType(allowedLicenseTypes, type) {
if (allowedLicenseTypes && allowedLicenseTypes.length) {
if (allowedLicenseTypes.includes(type)) {
return colors.green('✓');
}
testFailed = true;
return colors.red('x');
}
return '';
}
/**
* print package stats with relation to test limits
* @param {object} testConfig
* @param {number} testConfig.maxSizeBites
* @param {number} testConfig.maxPackagesNumber
* @param {string[]} testConfig.allowedLicenseTypes
* @param {object} packages
*/
function showPackageStats(
{
maxSizeBites,
maxPackagesNumber,
allowedLicenseTypes
}, packages
) {
const { count, size, licenseTypes } = getPackagesStats(packages);
readline.cursorTo(process.stdout, 0);
readline.clearLine(process.stdout);
const table = getSimpleTable();
table.push(
['Packages', count, '', getLimitResult(
count, maxPackagesNumber
)],
['Size', filesize(size), '', getLimitResult(size, maxSizeBites, filesize)]
);
Object.keys(licenseTypes).forEach((type, k) => {
table.push(
[
k === 0 ? 'Licenses' : '',
formatLicenseType(type),
licenseTypes[type],
checkLicenseType(allowedLicenseTypes, type)
]
);
});
console.log(table.toString());
}
module.exports = function install() {
getLocalPackage()
.then((localPackage) => {
const {
name, version, dependencies, devDependencies
} = localPackage;
console.log(colors.bold(
`${name}@${version}`
));
const allDependencies = {};
// TODO: dev and prod may have different versions of same dependency
Object.assign(
allDependencies,
dependencies || {}
);
if (!isProduction()) {
Object.assign(
allDependencies,
devDependencies || {}
);
}
return walkDependencies(
allDependencies
).then((packages) => {
showPackageStats(
getTestConfig(localPackage), packages
);
const [, options] = program.args;
if (options.test) {
// TODO: verify that test config is ok
if (testFailed) {
printError(`Limits provided in package.json are not satisfied`);
process.exit(1);
}
return;
}
return promptAction(packages);
});
})
.catch((e) => {
printError(e);
process.exit(1);
});
};