Skip to content

Commit 90ef5e5

Browse files
fix: writing TypeScript config file (#2114)
## PR Checklist - [x] Addresses an existing open issue: fixes #2113 - [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/TypeStat/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22) - [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/TypeStat/blob/main/.github/CONTRIBUTING.md) were taken ## Overview - Fixes issue where `null` was inserted to typestat.json `includes` list - Fixes issue where option was `inferableTypes` when it should be `noInferableTypes` - Added basic testing for config generation For future: - Config generation is still little bit broken. If I want to select just "Remove type annotations that don't change the meaning of code" option, the generated config file does not have it but instead has just `"incompleteTypes": true`. -> Needs new issue created. 🐙
1 parent 3c740f7 commit 90ef5e5

File tree

4 files changed

+160
-72
lines changed

4 files changed

+160
-72
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { describe, expect, it } from "vitest";
2+
3+
import { InitializationImprovement } from "./improvements.js";
4+
import { generateMultiTypeScriptConfig } from "./writeMultiTypeScriptConfig.js";
5+
6+
describe("writeMultiTypeScriptConfig", () => {
7+
it("creates multi TypeScript config", () => {
8+
const config = generateMultiTypeScriptConfig({
9+
fileName: "typestat.json",
10+
improvements: new Set([
11+
InitializationImprovement.MissingProperties,
12+
InitializationImprovement.NoImplicitAny,
13+
InitializationImprovement.NoImplicitThis,
14+
InitializationImprovement.NoInferableTypes,
15+
InitializationImprovement.StrictNullChecks,
16+
]),
17+
project: { filePath: "./tsconfig.json" },
18+
testFiles: "test/**/*.{ts,tsx}",
19+
});
20+
21+
expect(config).toStrictEqual([
22+
{
23+
fixes: {
24+
incompleteTypes: true,
25+
noImplicitAny: true,
26+
noImplicitThis: true,
27+
noInferableTypes: true,
28+
strictNonNullAssertions: true,
29+
},
30+
include: ["test/**/*.{ts,tsx}"],
31+
projectPath: "./tsconfig.json",
32+
types: {
33+
strictNullChecks: true,
34+
},
35+
},
36+
{
37+
fixes: {
38+
incompleteTypes: true,
39+
noImplicitAny: true,
40+
noImplicitThis: true,
41+
noInferableTypes: true,
42+
},
43+
include: undefined,
44+
projectPath: "./tsconfig.json",
45+
},
46+
{
47+
fixes: {
48+
incompleteTypes: true,
49+
noImplicitAny: true,
50+
noImplicitThis: true,
51+
noInferableTypes: true,
52+
},
53+
include: ["test/**/*.{ts,tsx}"],
54+
projectPath: "./tsconfig.json",
55+
},
56+
]);
57+
});
58+
});
Lines changed: 51 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import * as fs from "node:fs/promises";
22

3+
import { Fixes, RawTypeStatOptions } from "../../options/types.js";
4+
import { isNotUndefined } from "../../shared/arrays.js";
35
import { ProjectDescription } from "../initializeProject/shared.js";
46
import { InitializationImprovement } from "./improvements.js";
57

@@ -11,61 +13,62 @@ export interface MultiTypeScriptConfigSettings {
1113
testFiles?: string;
1214
}
1315

14-
export const writeMultiTypeScriptConfig = async ({
15-
fileName,
16+
export const writeMultiTypeScriptConfig = async (
17+
settings: MultiTypeScriptConfigSettings,
18+
) => {
19+
const config = generateMultiTypeScriptConfig(settings);
20+
await fs.writeFile(settings.fileName, JSON.stringify(config, undefined, 4));
21+
};
22+
23+
export const generateMultiTypeScriptConfig = ({
1624
improvements,
1725
project,
1826
sourceFiles,
1927
testFiles,
2028
}: MultiTypeScriptConfigSettings) => {
21-
await fs.writeFile(
22-
fileName,
23-
JSON.stringify(
24-
[
25-
{
26-
fixes: {
27-
...printImprovements(improvements),
28-
strictNonNullAssertions: true,
29-
},
30-
...(testFiles && { include: [testFiles] }),
31-
projectPath: project.filePath,
32-
types: {
33-
strictNullChecks: true,
34-
},
35-
},
36-
{
37-
...(testFiles && { exclude: [testFiles] }),
38-
fixes: printImprovements(improvements),
39-
...(sourceFiles && { include: [sourceFiles] }),
40-
projectPath: project.filePath,
41-
},
42-
{
43-
fixes: printImprovements(improvements),
44-
...(testFiles
45-
? { include: [testFiles, sourceFiles] }
46-
: { include: [sourceFiles] }),
47-
projectPath: project.filePath,
48-
},
49-
],
50-
undefined,
51-
4,
52-
),
53-
);
29+
const fixes = printImprovements(improvements);
30+
31+
const stage1: Partial<RawTypeStatOptions> = {
32+
fixes: {
33+
...fixes,
34+
strictNonNullAssertions: true,
35+
},
36+
include: testFiles ? [testFiles] : undefined,
37+
projectPath: project.filePath,
38+
types: {
39+
strictNullChecks: true,
40+
},
41+
};
42+
43+
const stage2: Partial<RawTypeStatOptions> = {
44+
fixes,
45+
include: sourceFiles ? [sourceFiles] : undefined,
46+
projectPath: project.filePath,
47+
};
48+
49+
const stage3Include = [testFiles, sourceFiles].filter(isNotUndefined);
50+
51+
const stage3: Partial<RawTypeStatOptions> = {
52+
fixes,
53+
include: stage3Include.length ? stage3Include : undefined,
54+
projectPath: project.filePath,
55+
};
56+
57+
return [stage1, stage2, stage3];
5458
};
5559

5660
const printImprovements = (
5761
improvements: ReadonlySet<InitializationImprovement>,
58-
) => {
59-
return {
60-
incompleteTypes: true,
61-
...(improvements.has(InitializationImprovement.NoImplicitAny) && {
62-
noImplicitAny: true,
63-
}),
64-
...(improvements.has(InitializationImprovement.NoInferableTypes) && {
65-
inferableTypes: true,
66-
}),
67-
...(improvements.has(InitializationImprovement.NoImplicitThis) && {
68-
noImplicitThis: true,
69-
}),
70-
};
62+
): Partial<Fixes> => {
63+
const fixes: Partial<Fixes> = { incompleteTypes: true };
64+
if (improvements.has(InitializationImprovement.NoImplicitAny)) {
65+
fixes.noImplicitAny = true;
66+
}
67+
if (improvements.has(InitializationImprovement.NoInferableTypes)) {
68+
fixes.noInferableTypes = true;
69+
}
70+
if (improvements.has(InitializationImprovement.NoImplicitThis)) {
71+
fixes.noImplicitThis = true;
72+
}
73+
return fixes;
7174
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { describe, expect, it } from "vitest";
2+
3+
import { InitializationImprovement } from "./improvements.js";
4+
import { generateSingleTypeScriptConfig } from "./writeSingleTypeScriptConfig.js";
5+
6+
describe("writeMultiTypeScriptConfig", () => {
7+
it("creates multi TypeScript config", () => {
8+
const config = generateSingleTypeScriptConfig({
9+
fileName: "typestat.json",
10+
improvements: new Set([InitializationImprovement.NoImplicitAny]),
11+
project: { filePath: "./tsconfig.json" },
12+
});
13+
14+
expect(config).toStrictEqual({
15+
fixes: {
16+
incompleteTypes: true,
17+
noImplicitAny: true,
18+
},
19+
include: undefined,
20+
projectPath: "./tsconfig.json",
21+
});
22+
23+
expect(JSON.stringify(config)).toBe(
24+
'{"fixes":{"incompleteTypes":true,"noImplicitAny":true},"projectPath":"./tsconfig.json"}',
25+
);
26+
});
27+
});
Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as fs from "node:fs/promises";
22

3+
import { Fixes, RawTypeStatOptions } from "../../options/types.js";
34
import { ProjectDescription } from "../initializeProject/shared.js";
45
import { InitializationImprovement } from "./improvements.js";
56

@@ -10,36 +11,35 @@ export interface SingleTypeScriptConfigSettings {
1011
sourceFiles?: string;
1112
}
1213

13-
export const writeSingleTypeScriptConfig = async ({
14-
fileName,
14+
export const writeSingleTypeScriptConfig = async (
15+
settings: SingleTypeScriptConfigSettings,
16+
) => {
17+
const config = generateSingleTypeScriptConfig(settings);
18+
await fs.writeFile(settings.fileName, JSON.stringify(config, undefined, 4));
19+
};
20+
21+
export const generateSingleTypeScriptConfig = ({
1522
improvements,
1623
project,
1724
sourceFiles,
1825
}: SingleTypeScriptConfigSettings) => {
19-
await fs.writeFile(
20-
fileName,
21-
JSON.stringify(
22-
{
23-
fixes: printImprovements(improvements),
24-
...(sourceFiles && { include: [sourceFiles] }),
25-
projectPath: project.filePath,
26-
},
27-
undefined,
28-
4,
29-
),
30-
);
26+
const config: Partial<RawTypeStatOptions> = {
27+
fixes: printImprovements(improvements),
28+
include: sourceFiles ? [sourceFiles] : undefined,
29+
projectPath: project.filePath,
30+
};
31+
return config;
3132
};
3233

3334
const printImprovements = (
3435
improvements: ReadonlySet<InitializationImprovement>,
35-
) => {
36-
return {
37-
incompleteTypes: true,
38-
...(improvements.has(InitializationImprovement.NoImplicitAny) && {
39-
noImplicitAny: true,
40-
}),
41-
...(improvements.has(InitializationImprovement.NoImplicitThis) && {
42-
noImplicitThis: true,
43-
}),
44-
};
36+
): Partial<Fixes> => {
37+
const fixes: Partial<Fixes> = { incompleteTypes: true };
38+
if (improvements.has(InitializationImprovement.NoImplicitAny)) {
39+
fixes.noImplicitAny = true;
40+
}
41+
if (improvements.has(InitializationImprovement.NoImplicitThis)) {
42+
fixes.noImplicitThis = true;
43+
}
44+
return fixes;
4545
};

0 commit comments

Comments
 (0)