UNPKG

@eweilow/paket-cli

Version:

A simple CLI for updating JS packages throughout an entire workspace

198 lines 7.84 kB
"use strict"; 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