Skip to content

Commit b39d65f

Browse files
authoredDec 21, 2024··
fix: use Knip version from installed dependency (#1792)
## PR Checklist - [x] Addresses an existing open issue: fixes #1638 - [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22) - [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/create-typescript-app/blob/main/.github/CONTRIBUTING.md) were taken ## Overview Uses the same `readFileSafeAsJson` strategy as `writePackageJson`. 💖
1 parent d789679 commit b39d65f

File tree

7 files changed

+116
-33
lines changed

7 files changed

+116
-33
lines changed
 

‎knip.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"$schema": "https://unpkg.com/knip@latest/schema.json",
2+
"$schema": "https://unpkg.com/knip@5.41.0/schema.json",
33
"entry": ["script/*e2e.js", "src/index.ts!", "src/**/*.test.*"],
44
"ignoreDependencies": ["all-contributors-cli"],
55
"ignoreExportsUsedInFile": { "interface": true, "type": true },

‎script/__snapshots__/migrate-test-e2e.ts.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ exports[`expected file changes > knip.json 1`] = `
212212
+++ b/knip.json
213213
@@ ... @@
214214
{
215-
"$schema": "https://unpkg.com/knip@latest/schema.json",
215+
"$schema": "https://unpkg.com/knip@5.41.0/schema.json",
216216
- "entry": ["script/*e2e.js", "src/index.ts!", "src/**/*.test.*"],
217217
- "ignoreDependencies": ["all-contributors-cli"],
218218
+ "entry": ["src/index.ts!"],

‎src/next/blocks/blockKnip.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { base } from "../base.js";
22
import { blockDevelopmentDocs } from "./blockDevelopmentDocs.js";
33
import { blockGitHubActionsCI } from "./blockGitHubActionsCI.js";
44
import { blockPackageJson } from "./blockPackageJson.js";
5-
import { getPackageDependencies } from "./packageData.js";
5+
import { getPackageDependencies, getPackageDependency } from "./packageData.js";
66

77
export const blockKnip = base.createBlock({
88
about: {
@@ -41,7 +41,7 @@ export const blockKnip = base.createBlock({
4141
],
4242
files: {
4343
"knip.json": JSON.stringify({
44-
$schema: "https://unpkg.com/knip@latest/schema.json",
44+
$schema: `https://unpkg.com/knip@${getPackageDependency("knip")}/schema.json`,
4545
entry: ["src/index.ts!"],
4646
ignoreExportsUsedInFile: {
4747
interface: true,

‎src/next/blocks/packageData.ts

+25-20
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,33 @@ const packageData =
66
// Importing from above src/ would expand the TS build rootDir
77
require("../../../package.json") as typeof import("../../../package.json");
88

9-
const getPackageInner = (
9+
export function getPackageDependencies(...names: string[]) {
10+
return Object.fromEntries(
11+
names.map((name) => {
12+
return [name, getPackageDependency(name)];
13+
}),
14+
);
15+
}
16+
17+
export function getPackageDependency(name: string) {
18+
const version =
19+
getPackageInner("devDependencies", name) ??
20+
getPackageInner("dependencies", name);
21+
22+
if (!version) {
23+
throw new Error(
24+
`'${name} is neither in package.json's dependencies nor its devDependencies.`,
25+
);
26+
}
27+
28+
return version;
29+
}
30+
31+
function getPackageInner(
1032
key: "dependencies" | "devDependencies",
1133
name: string,
12-
) => {
34+
) {
1335
const inner = packageData[key];
1436

1537
return inner[name as keyof typeof inner] as string | undefined;
16-
};
17-
18-
export const getPackageDependencies = (...names: string[]) =>
19-
Object.fromEntries(
20-
names.map((name) => {
21-
const version =
22-
getPackageInner("devDependencies", name) ??
23-
getPackageInner("dependencies", name);
24-
25-
if (!version) {
26-
throw new Error(
27-
`'${name} is neither in package.json's dependencies nor its devDependencies.`,
28-
);
29-
}
30-
31-
return [name, version];
32-
}),
33-
);
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { describe, expect, it, vi } from "vitest";
2+
3+
import { createKnipConfig } from "./createKnipConfig.js";
4+
5+
const mockReadFileSafeAsJson = vi.fn();
6+
7+
vi.mock("../../../shared/readFileSafeAsJson.js", () => ({
8+
get readFileSafeAsJson() {
9+
return mockReadFileSafeAsJson;
10+
},
11+
}));
12+
13+
describe("createKnipConfig", () => {
14+
it("uses uses the knip version from package.json devDependencies when it exists", async () => {
15+
const version = "1.2.3";
16+
mockReadFileSafeAsJson.mockResolvedValueOnce({
17+
devDependencies: { knip: version },
18+
});
19+
20+
const packageJson = await createKnipConfig();
21+
22+
expect(JSON.parse(packageJson)).toEqual({
23+
$schema: `https://unpkg.com/knip@${version}/schema.json`,
24+
entry: ["src/index.ts!"],
25+
ignoreExportsUsedInFile: {
26+
interface: true,
27+
type: true,
28+
},
29+
project: ["src/**/*.ts!"],
30+
});
31+
});
32+
33+
it("uses version 'latest' when the package.json does not exist", async () => {
34+
mockReadFileSafeAsJson.mockResolvedValueOnce(undefined);
35+
36+
const packageJson = await createKnipConfig();
37+
38+
expect(JSON.parse(packageJson)).toEqual({
39+
$schema: `https://unpkg.com/knip@latest/schema.json`,
40+
entry: ["src/index.ts!"],
41+
ignoreExportsUsedInFile: {
42+
interface: true,
43+
type: true,
44+
},
45+
project: ["src/**/*.ts!"],
46+
});
47+
});
48+
49+
it("uses version 'latest' when the package.json exists but does not have knip in devDependencies", async () => {
50+
mockReadFileSafeAsJson.mockResolvedValueOnce({
51+
dependencies: {},
52+
});
53+
54+
const packageJson = await createKnipConfig();
55+
56+
expect(JSON.parse(packageJson)).toEqual({
57+
$schema: `https://unpkg.com/knip@latest/schema.json`,
58+
entry: ["src/index.ts!"],
59+
ignoreExportsUsedInFile: {
60+
interface: true,
61+
type: true,
62+
},
63+
project: ["src/**/*.ts!"],
64+
});
65+
});
66+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { readFileSafeAsJson } from "../../../shared/readFileSafeAsJson.js";
2+
import { PartialPackageData } from "../../../shared/types.js";
3+
import { formatJson } from "./formatters/formatJson.js";
4+
5+
export async function createKnipConfig() {
6+
const existingPackageJson = (await readFileSafeAsJson(
7+
"./package.json",
8+
)) as null | PartialPackageData;
9+
10+
return await formatJson({
11+
$schema: `https://unpkg.com/knip@${existingPackageJson?.devDependencies?.knip ?? "latest"}/schema.json`,
12+
entry: ["src/index.ts!"],
13+
ignoreExportsUsedInFile: {
14+
interface: true,
15+
type: true,
16+
},
17+
project: ["src/**/*.ts!"],
18+
});
19+
}

‎src/steps/writing/creation/rootFiles.ts

+2-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Options } from "../../../shared/types.js";
22
import { createCSpellConfig } from "./createCSpellConfig.js";
33
import { createDotGitignore } from "./createDotGitignore.js";
44
import { createESLintConfig } from "./createESLintConfig.js";
5+
import { createKnipConfig } from "./createKnipConfig.js";
56
import { createTsupConfig } from "./createTsupConfig.js";
67
import { formatIgnoreFile } from "./formatters/formatIgnoreFile.js";
78
import { formatJson } from "./formatters/formatJson.js";
@@ -96,15 +97,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9697
"cspell.json": await createCSpellConfig(options),
9798
}),
9899
...(!options.excludeLintKnip && {
99-
"knip.json": await formatJson({
100-
$schema: "https://unpkg.com/knip@latest/schema.json",
101-
entry: ["src/index.ts!"],
102-
ignoreExportsUsedInFile: {
103-
interface: true,
104-
type: true,
105-
},
106-
project: ["src/**/*.ts!"],
107-
}),
100+
"knip.json": await createKnipConfig(),
108101
}),
109102
"package.json": await writePackageJson(options),
110103
"tsconfig.json": await formatJson({

0 commit comments

Comments
 (0)
Please sign in to comment.