@eweilow/paket-cli
Version:
A simple CLI for updating JS packages throughout an entire workspace
198 lines • 7.84 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const chalk_1 = __importDefault(require("chalk"));
const detect_newline_1 = __importDefault(require("detect-newline"));
const fs_1 = require("fs");
const glob = __importStar(require("glob"));
const minimatch = __importStar(require("minimatch"));
const node_fetch_1 = __importDefault(require("node-fetch"));
const path = __importStar(require("path"));
const registry = process.env.PAKET_REGISTRY || "https://registry.npmjs.org";
const cache = new Map();
async function getLatest(packageName) {
if (cache.has(packageName)) {
return cache.get(packageName);
}
const url = new URL(`${registry}/${encodeURIComponent(packageName)}`).href;
const res = await node_fetch_1.default(url);
const json = await res.json();
cache.set(packageName, json);
return json;
}
function isPackageMatch(name, globs) {
return globs.some(el => el.match(name));
}
function readMatchingPackages(globs, deps, fetchNames) {
if (deps == null) {
return;
}
for (const dep in deps) {
if (isPackageMatch(dep, globs)) {
fetchNames.add(dep);
}
}
}
function selectLastVersion(versions, times) {
const sorted = versions.sort((a, b) => {
return +new Date(times[b]) - +new Date(times[a]);
});
return sorted;
}
async function updateMatchingPackages(actuallyUpdate, mode, globs, deps, prefix, type) {
if (deps == null) {
return [];
}
const changed = [];
for (const dep in deps) {
if (isPackageMatch(dep, globs)) {
const packageInfo = await getLatest(dep);
const oldVersion = deps[dep];
let newVersion;
if (mode === "latest") {
newVersion = prefix + packageInfo["dist-tags"].latest;
}
else {
const sortedVersions = selectLastVersion(Object.keys(packageInfo.versions), packageInfo.time);
newVersion = prefix + sortedVersions[0];
}
if (oldVersion !== newVersion) {
changed.push(`${dep} (${chalk_1.default.magenta(type)}): ${chalk_1.default.yellow(oldVersion)} -> ${chalk_1.default.green(newVersion)}`);
if (actuallyUpdate) {
deps[dep] = newVersion;
}
}
}
}
return changed;
}
async function main(mode, op, ...globs) {
const cwd = process.cwd();
console.log("Using root folder: %s", cwd);
console.log("Using registry '%s'", registry);
let updatePrefix;
switch (op) {
case "check":
updatePrefix = "Checking";
break;
case "update":
updatePrefix = "Updating";
break;
default:
throw new Error("Unknown operation: " + op);
}
switch (mode) {
case "any":
console.log("\n%s packages matching globs:", updatePrefix);
for (const g of globs) {
console.log(` - ${chalk_1.default.yellow(g)}`);
}
console.log("to the last published version.\n");
break;
case "latest":
console.log("\n%s packages matching globs:", updatePrefix);
for (const g of globs) {
console.log(` - ${chalk_1.default.yellow(g)}`);
}
console.log("to the latest version.\n");
break;
default:
throw new Error("Unknown mode: " + mode);
}
let ignorePaths = [
"old/**",
"OLD_DO_NOT_USE/**",
"update-excitare/**",
"node_modules/**",
"**/node_modules/**",
".git/**"
];
const ignorePath = path.join(cwd, "./.paketignore");
if (fs_1.existsSync(ignorePath)) {
ignorePaths = fs_1.readFileSync(ignorePath, "utf-8")
.split("\n")
.map(el => el.trim());
}
console.log("Using ignore paths:\n%s", ignorePaths.map(el => ` - '${el}'`).join("\n"));
const files = glob
.sync("**/package.json", {
ignore: ignorePaths,
cwd
})
.map(name => path.join(cwd, name));
const mappedGlobs = globs.map(el => new minimatch.Minimatch(el));
const packages = new Map();
const fetchNames = new Set();
for (const file of files) {
// tslint:disable-next-line:no-var-requires
const pkg = require(file);
if (pkg.resolveModules) {
for (const name of pkg.resolveModules) {
fetchNames.add(name);
}
}
packages.set(file, pkg);
readMatchingPackages(mappedGlobs, pkg.dependencies, fetchNames);
readMatchingPackages(mappedGlobs, pkg.devDependencies, fetchNames);
readMatchingPackages(mappedGlobs, pkg.peerDependencies, fetchNames);
readMatchingPackages(mappedGlobs, pkg.optionalDependencies, fetchNames);
}
await Promise.all([...fetchNames].map(name => getLatest(name)));
let someChanged = false;
for (const [file, pkg] of packages) {
const resolutions = {};
if (pkg.resolveModules) {
for (const name of pkg.resolveModules) {
resolutions[name] = pkg.resolutions != null ? pkg.resolutions["**/" + name] : "unset";
}
}
const changed = [];
changed.push(...(await updateMatchingPackages(op === "update", mode, mappedGlobs, pkg.dependencies, "^", "normal")));
changed.push(...(await updateMatchingPackages(op === "update", mode, mappedGlobs, pkg.devDependencies, "^", "dev")));
changed.push(...(await updateMatchingPackages(op === "update", mode, mappedGlobs, pkg.peerDependencies, "^", "peer")));
changed.push(...(await updateMatchingPackages(op === "update", mode, mappedGlobs, pkg.optionalDependencies, "^", "optional")));
changed.push(...(await updateMatchingPackages(op === "update", mode, mappedGlobs, resolutions, "", "resolutions")));
if (Object.keys(resolutions).length > 0) {
pkg.resolutions = pkg.resolutions || {};
for (const key of Object.keys(resolutions)) {
pkg.resolutions["**/" + key] = resolutions[key];
}
}
if (changed.length > 0) {
someChanged = true;
const changedSet = new Set(changed);
console.log(`${chalk_1.default.cyan(pkg.name)}:`);
for (const changedPkg of changedSet) {
console.log(" " + changedPkg);
}
}
if (op === "update") {
const existing = fs_1.readFileSync(file).toString("utf-8");
const endings = detect_newline_1.default(existing);
if (endings != null) {
const newData = JSON.stringify(pkg, null, " ") + endings;
if (newData !== existing) {
fs_1.writeFileSync(file, newData.replace(/\r?\n/g, endings));
}
}
}
}
if (!someChanged) {
console.log("No updates required.");
}
console.log("");
}
main(process.argv[3], process.argv[2], ...process.argv.slice(4)).catch(err => {
console.error(err);
process.exit(1);
});
//# sourceMappingURL=index.js.map
;