updates/updates.js

136 lines
3.3 KiB
JavaScript
Raw Normal View History

2017-12-03 11:15:02 +00:00
#!/usr/bin/env node
"use strict";
const cli = require("meow")(`
Options:
2017-12-03 11:18:28 +00:00
--update, -u Also update package.json
2017-12-03 12:17:31 +00:00
--json, -j Output JSON
2017-12-03 11:15:02 +00:00
Examples:
$ updates
2017-12-03 11:35:25 +00:00
$ updates -u
2017-12-03 11:15:02 +00:00
`);
const fs = require("fs");
2017-12-03 12:17:31 +00:00
const os = require("os");
2017-12-03 11:15:02 +00:00
const got = require("got");
const path = require("path");
const semver = require("semver");
const columnify = require("columnify");
const chalk = require("chalk");
const esc = require("escape-string-regexp");
const pkgStr = fs.readFileSync(path.join(process.cwd(), "package.json"), "utf8");
const pkg = JSON.parse(pkgStr);
const url = "https://registry.npmjs.org/";
const deps = [];
[
"dependencies",
"devDependencies",
"peerDependencies",
"bundledDependencies",
"optionalDependencies"
].forEach(function(key) {
if (pkg[key]) {
Object.keys(pkg[key]).forEach(function(name) {
const range = pkg[key][name];
if (isValidSemverRange(range)) {
deps.push({name, range});
}
});
}
});
Promise.all(deps.map(dep => got(`${url}${dep.name}`))).then(function(responses) {
return responses.map(function(response, i) {
const dep = Object.keys(deps)[i];
const name = deps[dep].name;
const range = deps[dep].range;
const newVersion = JSON.parse(response.body)["dist-tags"]["latest"];
const newRange = updateRange(range, newVersion);
return {name, range, newRange};
});
}).then(function(results) {
2017-12-03 12:17:31 +00:00
results = results.filter(function(result) {
2017-12-03 11:15:02 +00:00
return result.range !== result.newRange;
});
2017-12-03 12:17:31 +00:00
if (!results.length) {
print("All packages are up to date.");
2017-12-03 11:15:02 +00:00
process.exit(0);
2017-12-03 11:18:28 +00:00
} else if (!cli.flags.u && !cli.flags.update) {
2017-12-03 12:17:31 +00:00
if (cli.flags.j || cli.flags.json) {
print(results);
} else {
print(formatResults(results));
}
2017-12-03 11:15:02 +00:00
process.exit(0);
}
return results;
}).then(function(results) {
2017-12-03 11:18:28 +00:00
fs.writeFile("package.json", updatePkg(results), "utf8", function(err) {
2017-12-03 11:15:02 +00:00
if (err) {
2017-12-03 12:17:31 +00:00
print(err);
2017-12-03 11:15:02 +00:00
process.exit(1);
} else {
2017-12-03 12:17:31 +00:00
print("package.json updated!");
2017-12-03 11:15:02 +00:00
process.exit(0);
}
});
});
2017-12-03 12:17:31 +00:00
function print(obj) {
if (cli.flags.j || cli.flags.json) {
if (typeof obj === "string") {
obj = {message: obj};
} else if (obj instanceof Error) {
obj = {error: obj.message};
}
process.stdout.write(JSON.stringify(obj, null, 2) + os.EOL);
} else {
if (obj instanceof Error) {
process.stderr.write(obj + os.EOL);
} else {
process.stdout.write(obj + os.EOL);
}
}
}
2017-12-03 11:15:02 +00:00
function formatResults(results) {
return columnify(results.map(r => Object.assign({}, r)).map(function(output) {
if (output.newRange !== output.range) {
return {
name: output.name,
2017-12-03 12:20:37 +00:00
old: chalk.red(output.range),
"new": chalk.green(output.newRange),
2017-12-03 11:15:02 +00:00
};
}
2017-12-03 12:17:31 +00:00
}), {
2017-12-03 11:15:02 +00:00
columnSplitter: " ",
});
}
2017-12-03 11:18:28 +00:00
function updatePkg(results) {
2017-12-03 11:15:02 +00:00
let newPkgStr = pkgStr;
results.forEach(function(result) {
const re = new RegExp(`"${esc(result.name)}": +"${esc(result.range)}"`, "g");
newPkgStr = newPkgStr.replace(re, `"${result.name}": "${result.newRange}"`);
});
return newPkgStr;
}
// naive regex replace
function updateRange(range, version) {
return range.replace(/[0-9]+\.[0-9]+\.[0-9](-.+)?/, version);
}
function isValidSemverRange(range) {
let valid = false;
try {
semver.Range(range);
valid = true;
} catch (err) {}
return valid;
}