UNPKG

@manypkg/cli

Version:

Manypkg is a linter for `package.json` files in Yarn, npm, Lerna, pnpm or Rush monorepos.

180 lines (169 loc) 4.75 kB
import path from "node:path"; import * as logger from "./logger.ts"; import { getPackages, type Packages, type Package, } from "@manypkg/get-packages"; import type { Options } from "./checks/utils.ts"; import { checks } from "./checks/index.ts"; import { ExitError } from "./errors.ts"; import { writePackage, install } from "./utils.ts"; import { runCmd } from "./run.ts"; import { upgradeDependency } from "./upgrade.ts"; import { npmTagAll } from "./npm-tag.ts"; import { exec } from "tinyexec"; import pLimit from "p-limit"; type RootPackage = Package & { packageJson: { manypkg?: Options; }; }; type PackagesWithConfig = Packages & { rootPackage?: RootPackage; }; let defaultOptions = { defaultBranch: "main", }; let runChecks = ( allWorkspaces: Map<string, Package>, rootWorkspace: RootPackage | undefined, shouldFix: boolean, options: Options ) => { let hasErrored = false; let requiresInstall = false; let ignoredRules = new Set(options.ignoredRules || []); for (let [ruleName, check] of Object.entries(checks)) { if (ignoredRules.has(ruleName)) { continue; } if (check.type === "all") { for (let [, workspace] of allWorkspaces) { let errors = check.validate( workspace, allWorkspaces, rootWorkspace, options ); if (shouldFix && check.fix !== undefined) { for (let error of errors) { let output = check.fix(error as any, options) || { requiresInstall: false, }; if (output.requiresInstall) { requiresInstall = true; } } } else { for (let error of errors) { hasErrored = true; logger.error(check.print(error as any, options)); } } } } if (check.type === "root" && rootWorkspace) { let errors = check.validate(rootWorkspace, allWorkspaces, options); if (shouldFix && check.fix !== undefined) { for (let error of errors) { let output = check.fix(error as any, options) || { requiresInstall: false, }; if (output.requiresInstall) { requiresInstall = true; } } } else { for (let error of errors) { hasErrored = true; logger.error(check.print(error as any, options)); } } } } return { requiresInstall, hasErrored }; }; let execLimit = pLimit(4); async function execCmd(args: string[]) { let { packages } = await getPackages(process.cwd()); let highestExitCode = 0; await Promise.all( packages.map((pkg) => { return execLimit(async () => { const { exitCode } = await exec(args[0], args.slice(1), { nodeOptions: { cwd: pkg.dir, stdio: "inherit", }, }); highestExitCode = Math.max(exitCode ?? 1, highestExitCode); }); }) ); throw new ExitError(highestExitCode); } (async () => { let things = process.argv.slice(2); if (things[0] === "exec") { return execCmd(things.slice(1)); } if (things[0] === "run") { return runCmd(things.slice(1), process.cwd()); } if (things[0] === "upgrade") { return upgradeDependency(things.slice(1)); } if (things[0] === "npm-tag") { return npmTagAll(things.slice(1)); } if (things[0] !== "check" && things[0] !== "fix") { logger.error( `command ${things[0]} not found, only check, exec, run, upgrade, npm-tag and fix exist` ); throw new ExitError(1); } let shouldFix = things[0] === "fix"; let { tool, packages, rootPackage, rootDir } = (await getPackages( process.cwd() )) as PackagesWithConfig; let options: Options = { ...defaultOptions, ...rootPackage?.packageJson.manypkg, }; let packagesByName = new Map<string, Package>( packages.map((x) => [x.packageJson.name, x]) ); if (rootPackage) { packagesByName.set(rootPackage.packageJson.name, rootPackage); } let { hasErrored, requiresInstall } = runChecks( packagesByName, rootPackage, shouldFix, options ); if (shouldFix) { await Promise.all( [...packagesByName].map(async ([pkgName, workspace]) => { writePackage(workspace); }) ); if (requiresInstall) { await install(tool.type, rootDir); } logger.success(`fixed workspaces!`); } else if (hasErrored) { logger.info(`the above errors may be fixable with yarn manypkg fix`); throw new ExitError(1); } else { logger.success(`workspaces valid!`); } })().catch((err) => { if (err instanceof ExitError) { process.exit(err.code); } else { logger.error(err); process.exit(1); } });