npmcheck.js

This script parses a package.json file and checks NPM for updates to all dependencies.


javascript
#!/usr/bin/env node

const path = require('path');
const exec = require('child_process').exec;
const cwd = process.cwd();
let dir = process.argv[2];

if (!dir) {
	dir = cwd;
}

if (!path.isAbsolute(dir)) {
	dir = path.resolve(dir);
}
const pkg = require(path.join(dir, 'package.json'));

const deps = pkg.dependencies || {};
const devDeps = pkg.devDependencies || {};

const green = `\u001b[32m`;
const red = `\u001b[31m`;
const cyan = `\u001b[36m`;
const blue = `\u001b[34m`;
const bold = `\u001b[1m`;
const underline = `\u001b[4m`;
const reset = `\u001b[0m`;

const results = {
	deps: {},
	devDeps: {},
};

const pending = Object.keys(deps).map(name => ({ name, currentVersion: deps[name] }))
	.concat(Object.keys(devDeps).map(name => ({name, currentVersion: devDeps[name]})));

const stats = {
	inFlight: 0,
	total: pending.length,
	processed: 0,
	failed: 0,
};

const printProgress = () => {
	process.stdout.write('\r' + ' '.repeat(70));
	process.stdout.write(`\r${bold}${stats.processed}/${stats.total}${reset} dependencies checked (${stats.inFlight} in flight)`);
};

const check = async (name, currentVersion) => {
	stats.inFlight++;
	printProgress();

	return new Promise((resolve, reject) => {
		exec(`npm info ${name} version`, (err, stdout) => {
			stats.processed++;
			stats.inFlight--;

			if (err) {
				stats.failed++;
			}

			printProgress();

			const version = (stdout || '').trim() || '???';

			if (deps[name]) {
				results.deps[name] = {
					current: currentVersion,
					latest: version,
				}
			} else {
				results.devDeps[name] = {
					current: currentVersion,
					latest: version,
				}
			}

			resolve(runNext());
		});
	});
};

const runNext = () => {
	const next = pending.shift();
	if (next) {
		return check(next.name, next.currentVersion);
	}

	return Promise.resolve();
};

const maxInFlight = 5;
const promises = [];
for (let i = 0; i < maxInFlight; i++) {
	const next = pending.shift();
	if (!next) {
		break;
	}

	promises.push(check(next.name, next.currentVersion));
}

Promise.all(promises)
	.then(() => {
		console.log('\r' + ' '.repeat(70));
		const maxLength = Object.keys(results.deps)
			.concat(Object.keys(results.devDeps))
			.reduce((max, name) => Math.max(max, name.length), 30);

		const print = (deps) => {
			Object.keys(deps).sort().forEach((name) => {
				const value = deps[name];
				const isCurrent = value.current === value.latest;
				console.log(`${blue}${name}${reset}  ` + '.'.repeat(maxLength - name.length + 5) + ' ' +
					(isCurrent ? `${green}${value.current}${reset}` : `${red}${value.current}${reset}${bold}${cyan}${value.latest}${reset}`));
			});
		};

		console.log(`${bold}${underline}Dependencies${reset}`);
		print(results.deps);

		console.log();

		console.log(`${bold}${underline}Dev Dependencies${reset}`);
		print(results.devDeps);

		console.log();

		process.exit();
	})
	.catch((err) => {
		console.error(err);
		process.exit(1);
	});

Sample output

npmcheck.js in action