Skip to content

Commit 5127bcb

Browse files
fix: don't pnpm remove an empty list of packages (#727)
<!-- 👋 Hi, thanks for sending a PR to template-typescript-node-package! 💖. Please fill out all fields below and make sure each item is true and [x] checked. Otherwise we may not be able to review your PR. --> ## PR Checklist - [x] Addresses an existing open issue: fixes #724 - [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/template-typescript-node-package/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22) - [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/template-typescript-node-package/blob/main/.github/CONTRIBUTING.md) were taken ## Overview Refactors the two existing package removal functions to be just one.
1 parent de0f5a3 commit 5127bcb

File tree

5 files changed

+85
-33
lines changed

5 files changed

+85
-33
lines changed

src/shared/packages.test.ts

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { describe, expect, it, vi } from "vitest";
2+
3+
import { removeDependencies } from "./packages.js";
4+
5+
const mockExecaCommand = vi.fn();
6+
7+
vi.mock("execa", () => ({
8+
get execaCommand() {
9+
return mockExecaCommand;
10+
},
11+
}));
12+
13+
describe("removeDependencies", () => {
14+
it("removes all packages that already exist when all already exist", async () => {
15+
await removeDependencies(["one", "two"], {
16+
one: "1.2.3",
17+
two: "4.5.6",
18+
});
19+
20+
expect(mockExecaCommand.mock.calls).toMatchInlineSnapshot(`
21+
[
22+
[
23+
"pnpm remove one two",
24+
],
25+
]
26+
`);
27+
});
28+
29+
it("removes only packages that already exist when some don't exist", async () => {
30+
await removeDependencies(["exists", "missing"], {
31+
exists: "1.2.3",
32+
});
33+
34+
expect(mockExecaCommand.mock.calls).toMatchInlineSnapshot(`
35+
[
36+
[
37+
"pnpm remove exists",
38+
],
39+
]
40+
`);
41+
});
42+
43+
it("adds a flag to removing packages when one is provided", async () => {
44+
await removeDependencies(
45+
["exists", "missing"],
46+
{
47+
exists: "1.2.3",
48+
},
49+
"-D",
50+
);
51+
52+
expect(mockExecaCommand.mock.calls).toMatchInlineSnapshot(`
53+
[
54+
[
55+
"pnpm remove exists -D",
56+
],
57+
]
58+
`);
59+
});
60+
61+
it("does nothing when no packages already exist", async () => {
62+
await removeDependencies(["missing"]);
63+
64+
expect(mockExecaCommand.mock.calls).toMatchInlineSnapshot("[]");
65+
});
66+
});

src/shared/packages.ts

+9-17
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { $ } from "execa";
1+
import { execaCommand } from "execa";
22

33
import { readFileSafe } from "./readFileSafe.js";
44
import { PartialPackageData } from "./types.js";
@@ -11,22 +11,14 @@ export async function readPackageData() {
1111

1212
export async function removeDependencies(
1313
packageNames: string[],
14-
packageData: PartialPackageData,
14+
existing: Record<string, string> = {},
15+
flags = "",
1516
) {
16-
await $`pnpm remove ${packageNames.filter(
17-
packageExists(packageData.dependencies),
18-
)}`;
19-
}
20-
21-
export async function removeDevDependencies(
22-
packageNames: string[],
23-
packageData: PartialPackageData,
24-
) {
25-
await $`pnpm remove ${packageNames.filter(
26-
packageExists(packageData.devDependencies),
27-
)} -D`;
28-
}
17+
const present = packageNames.filter((packageName) => packageName in existing);
2918

30-
function packageExists(listing: Record<string, string> = {}) {
31-
return (packageName: string) => packageName in listing;
19+
if (present.length) {
20+
await execaCommand(
21+
`pnpm remove ${present.join(" ")}${flags ? ` ${flags}` : ""}`,
22+
);
23+
}
3224
}

src/steps/finalizeDependencies.test.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,9 @@ vi.mock("execa", () => ({
1111
},
1212
}));
1313

14-
const mockRemoveDevDependencies = vi.fn();
15-
1614
vi.mock("../shared/packages.js", () => ({
1715
readPackageData: () => [],
18-
get removeDevDependencies() {
19-
return mockRemoveDevDependencies;
20-
},
16+
removeDependencies: vi.fn(),
2117
}));
2218

2319
const options = {

src/steps/finalizeDependencies.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { execaCommand } from "execa";
22

3-
import { readPackageData, removeDevDependencies } from "../shared/packages.js";
3+
import { readPackageData, removeDependencies } from "../shared/packages.js";
44
import { Options } from "../shared/types.js";
55

66
export async function finalizeDependencies(options: Options) {
@@ -68,9 +68,10 @@ export async function finalizeDependencies(options: Options) {
6868

6969
if (!options.excludeContributors) {
7070
await execaCommand(`npx all-contributors-cli generate`);
71-
await removeDevDependencies(
71+
await removeDependencies(
7272
["all-contributors-cli", "all-contributors-for-repository"],
73-
await readPackageData(),
73+
(await readPackageData()).devDependencies,
74+
"-D",
7475
);
7576
}
7677

src/steps/uninstallPackages.ts

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import { $ } from "execa";
22

3-
import {
4-
readPackageData,
5-
removeDependencies,
6-
removeDevDependencies,
7-
} from "../shared/packages.js";
3+
import { readPackageData, removeDependencies } from "../shared/packages.js";
84

95
export async function uninstallPackages() {
106
const packageData = await readPackageData();
@@ -24,10 +20,10 @@ export async function uninstallPackages() {
2420
"replace-in-file",
2521
"title-case",
2622
],
27-
packageData,
23+
packageData.dependencies,
2824
);
2925

30-
await removeDevDependencies(
26+
await removeDependencies(
3127
[
3228
"@octokit/request-error",
3329
"@types/git-url-parse",
@@ -38,7 +34,8 @@ export async function uninstallPackages() {
3834
"globby",
3935
"tsx",
4036
],
41-
packageData,
37+
packageData.devDependencies,
38+
"-D",
4239
);
4340

4441
await $`pnpm add prettier -D`;

0 commit comments

Comments
 (0)