Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: support multiple package managers #177

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/real-points-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@arethetypeswrong/cli": minor
---

Add support for multiple package managers like [pnpm](https://pnpm.io/) and [yarn](https://yarnpkg.com/) ([#173](https://github.com/arethetypeswrong/arethetypeswrong.github.io/issues/173))
4 changes: 3 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@types/marked-terminal": "^3.1.3",
"@types/node": "^20.2.5",
"@types/semver": "^7.5.3",
"@types/which-pm-runs": "^1.0.2",
"ts-expose-internals-conditionally": "1.0.0-empty.0",
"typescript": "5.3.3"
},
Expand All @@ -59,7 +60,8 @@
"commander": "^10.0.1",
"marked": "^9.1.2",
"marked-terminal": "^6.0.0",
"semver": "^7.5.4"
"semver": "^7.5.4",
"which-pm-runs": "^1.1.0"
},
"engines": {
"node": ">=18"
Expand Down
25 changes: 14 additions & 11 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { readConfig } from "./readConfig.js";
import * as render from "./render/index.js";
import { major, minor } from "semver";
import { getExitCode } from "./getExitCode.js";
import { determinePackCommand, determineTarballFilename } from "./utils.js";
import detectPackageManager from "which-pm-runs";

const packageJson = createRequire(import.meta.url)("../package.json");
const version = packageJson.version;
Expand Down Expand Up @@ -74,8 +76,8 @@ particularly ESM-related module resolution issues.`,
.option("--exclude-entrypoints <entrypoints...>", "Specify entrypoints to exclude from checking.")
.option(
"--entrypoints-legacy",
'In packages without the `exports` field, every file is an entry point. Specifying this option ' +
'only takes effect when no entrypoints are automatically detected, or explicitly provided with other options.'
"In packages without the `exports` field, every file is an entry point. Specifying this option " +
"only takes effect when no entrypoints are automatically detected, or explicitly provided with other options.",
)
.addOption(
new Option("--ignore-rules <rules...>", "Specify rules to ignore").choices(Object.values(problemFlags)).default([]),
Expand Down Expand Up @@ -159,29 +161,30 @@ particularly ESM-related module resolution issues.`,
);
}

const packageManager = (await detectPackageManager()?.name) ?? "npm";
const packCommand = determinePackCommand(packageManager);

if (!opts.pack) {
if (!process.stdout.isTTY) {
program.error(
"Specifying a directory requires the --pack option to confirm that running `npm pack` is ok.",
`Specifying a directory requires the --pack option to confirm that running \`${packCommand}\` is ok.`,
);
}
const rl = readline.createInterface(process.stdin, process.stdout);
const answer = await new Promise<string>((resolve) => {
rl.question(`Run \`npm pack\`? (Pass -P/--pack to skip) (Y/n) `, resolve);
rl.question(`Run \`${packCommand}\`? (Pass -P/--pack to skip) (Y/n) `, resolve);
});
rl.close();
if (answer.trim() && !answer.trim().toLowerCase().startsWith("y")) {
process.exit(1);
}
}

const manifest = JSON.parse(await readFile(path.join(fileOrDirectory, "package.json"), { encoding: "utf8" }));
fileName = deleteTgz = path.join(
fileOrDirectory,
// https://github.com/npm/cli/blob/f875caa86900122819311dd77cde01c700fd1817/lib/utils/tar.js#L123-L125
`${manifest.name.replace("@", "").replace("/", "-")}-${manifest.version}.tgz`,
);
execSync("npm pack", { cwd: fileOrDirectory, encoding: "utf8", stdio: "ignore" });
fileName = deleteTgz = await determineTarballFilename(fileOrDirectory);

const packCommandWithFilename = determinePackCommand(packageManager, fileName);

execSync(packCommandWithFilename, { cwd: fileOrDirectory, encoding: "utf8", stdio: "ignore" });
}
const file = await readFile(fileName);
const data = new Uint8Array(file);
Expand Down
26 changes: 26 additions & 0 deletions packages/cli/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { readFile } from "fs/promises";
import path from "path";

/** Determine which CLI command to use to create a tarball from a package. */
export const determinePackCommand = (packageManager: string, filename?: string) => {
switch (packageManager) {
case "pnpm":
// PNPM does not support custom destination filenames (see: https://github.com/pnpm/pnpm/issues/7834)
return "pnpm pack";
case "yarn":
return filename ? `yarn pack --out ${filename}` : "yarn pack";
default:
return filename ? `npm pack ${filename}` : "npm pack";
}
};

/** Determine which tarball filename to use. */
export const determineTarballFilename = async (fileOrDirectory: string) => {
const manifest = JSON.parse(await readFile(path.join(fileOrDirectory, "package.json"), { encoding: "utf8" }));

return path.join(
fileOrDirectory,
// https://github.com/npm/cli/blob/f875caa86900122819311dd77cde01c700fd1817/lib/utils/tar.js#L123-L125
`${manifest.name.replace("@", "").replace("/", "-")}-${manifest.version}.tgz`,
);
};
Loading
Loading