Skip to content

Commit 3e1e69b

Browse files
fix: improve reading tsconfig (#2192)
## PR Checklist - [x] Addresses an existing open issue: fixes #1532 - [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 I have taken inspiration how to do this from `ts-fix`. They are doing it with `ts.getParsedCommandLineOfConfigFile` so I think that is what would be the best way here too. I also reworked testSetup so it uses more same code as the whole tool. `cwd` is passed down from `runCli` so we can supply it in the test easier. `printers.node` uses now the existing SourceFile so we do not need to create dummy SourceFile for it. I didn't see behaviour change but I think it should be better this way. Now it can use the context from original SourceFile. Most changes are in the test files.
1 parent d50212f commit 3e1e69b

File tree

56 files changed

+1810
-700
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1810
-700
lines changed

src/cli/runCli.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ export const runCli = async (
6363
let result: TypeStatResult;
6464

6565
try {
66-
result = await runtime.mainRunner(rawOptions.config, runtime.output);
66+
result = await runtime.mainRunner(
67+
rawOptions.config,
68+
process.cwd(),
69+
runtime.output,
70+
);
6771
} catch (error) {
6872
result = {
6973
error: error instanceof Error ? error : new Error(error as string),

src/index.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ export type TypeStatResult =
4545

4646
export const typeStat = async (
4747
configPath: string | undefined,
48+
cwd: string,
4849
output: ProcessOutput,
4950
): Promise<TypeStatResult> => {
50-
const allPendingOptions = await tryLoadingPendingOptions(configPath, output);
51+
const allPendingOptions = tryLoadingPendingOptions(configPath, cwd, output);
5152
if (
5253
allPendingOptions instanceof Error ||
5354
typeof allPendingOptions === "string"
@@ -90,10 +91,7 @@ export const typeStat = async (
9091

9192
for (let i = 0; i < allPendingOptions.length; i += 1) {
9293
// Collect all files to be run on this option iteration from the include glob(s)
93-
const fileNames = await collectFileNames(
94-
process.cwd(),
95-
allPendingOptions[i].include,
96-
);
94+
const fileNames = await collectFileNames(cwd, allPendingOptions[i].include);
9795
if (typeof fileNames !== "object") {
9896
return {
9997
error: new Error(
@@ -144,12 +142,13 @@ export const typeStat = async (
144142
};
145143
};
146144

147-
const tryLoadingPendingOptions = async (
145+
const tryLoadingPendingOptions = (
148146
configPath: string | undefined,
147+
cwd: string,
149148
output: ProcessOutput,
150-
): Promise<Error | PendingTypeStatOptions[] | string> => {
149+
): Error | PendingTypeStatOptions[] | string => {
151150
try {
152-
return await loadPendingOptions(configPath, output);
151+
return loadPendingOptions(configPath, cwd, output);
153152
} catch (error) {
154153
return error instanceof Error ? error : new Error(error as string);
155154
}

src/mutations/creations/creationMutations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const createDeclarationForTypeSummaries = (
1616
enclosingDeclaration,
1717
typeSummaries,
1818
);
19-
const newLine = printNewLine(request.options.compilerOptions);
19+
const newLine = printNewLine(request.options.parsedTsConfig.options);
2020

2121
return [`type ${name} = {`, newLine, printedSummaries, `};`].join("");
2222
};

src/mutators/builtIn/fixIncompleteTypes/fixIncompleteImplicitGenerics/additions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const addNewTypeNodes = (
88
node: ts.ClassLikeDeclaration,
99
createdTypes: string[],
1010
) => {
11-
const endline = printNewLine(request.options.compilerOptions);
11+
const endline = printNewLine(request.options.parsedTsConfig.options);
1212

1313
return {
1414
insertion: `${endline}${createdTypes.join(endline)}`,

src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsFromPropTypes/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,11 @@ const createInterfaceCreationMutation = (
8989
node: ReactComponentNode,
9090
interfaceNode: ts.InterfaceDeclaration,
9191
): TextInsertMutation => {
92-
const endline = printNewLine(request.options.compilerOptions);
93-
const interfaceNodeText = request.services.printers.node(interfaceNode);
92+
const endline = printNewLine(request.options.parsedTsConfig.options);
93+
const interfaceNodeText = request.services.printers.node(
94+
interfaceNode,
95+
request.sourceFile,
96+
);
9497

9598
return {
9699
insertion: [endline, endline, interfaceNodeText, endline].join(""),

src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/fixReactPropsMissing.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ const createPropsTypeCreationMutation = (
190190
interfaceName: string,
191191
{ attributeTypes, requiredAttributeNames }: AttributeTypesAndRequirements,
192192
) => {
193-
const endline = printNewLine(request.options.compilerOptions);
193+
const endline = printNewLine(request.options.parsedTsConfig.options);
194194

195195
return {
196196
insertion: [

src/mutators/builtIn/fixIncompleteTypes/fixIncompleteReactTypes/reactFiltering/reactUsageFiltering.ts

Whitespace-only changes.

src/options/fillOutRawOptions.ts

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import ts from "typescript";
2+
13
import { ProcessOutput } from "../output/types.js";
24
import { collectOptionals } from "../shared/arrays.js";
35
import { ReactPropTypesHint, ReactPropTypesOptionality } from "./enums.js";
4-
import { ParsedCompilerOptions } from "./parseRawCompilerOptions.js";
56
import { collectAddedMutators } from "./parsing/collectAddedMutators.js";
67
import { collectFileOptions } from "./parsing/collectFileOptions.js";
78
import { collectNoImplicitAny } from "./parsing/collectNoImplicitAny.js";
@@ -11,9 +12,9 @@ import { collectStrictNullChecks } from "./parsing/collectStrictNullChecks.js";
1112
import { PendingTypeStatOptions, RawTypeStatOptions } from "./types.js";
1213

1314
export interface OptionsFromRawOptionsSettings {
14-
compilerOptions: Readonly<ParsedCompilerOptions>;
1515
cwd: string;
1616
output: ProcessOutput;
17+
parsedTsConfig: Readonly<ts.ParsedCommandLine>;
1718
projectPath: string;
1819
rawOptions: RawTypeStatOptions;
1920
}
@@ -23,17 +24,23 @@ export interface OptionsFromRawOptionsSettings {
2324
* @returns Parsed TypeStat options, or a string for an error complaint.
2425
*/
2526
export const fillOutRawOptions = ({
26-
compilerOptions,
2727
cwd,
2828
output,
29+
parsedTsConfig,
2930
projectPath,
3031
rawOptions,
3132
}: OptionsFromRawOptionsSettings): PendingTypeStatOptions => {
3233
const rawOptionTypes = rawOptions.types ?? {};
33-
const noImplicitAny = collectNoImplicitAny(compilerOptions, rawOptions);
34-
const noImplicitThis = collectNoImplicitThis(compilerOptions, rawOptions);
34+
const noImplicitAny = collectNoImplicitAny(
35+
parsedTsConfig.options,
36+
rawOptions,
37+
);
38+
const noImplicitThis = collectNoImplicitThis(
39+
parsedTsConfig.options,
40+
rawOptions,
41+
);
3542
const { compilerStrictNullChecks, typeStrictNullChecks } =
36-
collectStrictNullChecks(compilerOptions, rawOptionTypes);
43+
collectStrictNullChecks(parsedTsConfig.options, rawOptionTypes);
3744

3845
const packageOptions = collectPackageOptions(cwd, rawOptions);
3946

@@ -47,12 +54,6 @@ export const fillOutRawOptions = ({
4754
suppressTypeErrors: false,
4855
...rawOptions.cleanups,
4956
},
50-
compilerOptions: {
51-
...compilerOptions,
52-
noImplicitAny,
53-
noImplicitThis,
54-
strictNullChecks: compilerStrictNullChecks,
55-
},
5657
files: collectFileOptions(rawOptions),
5758
filters: collectOptionals(rawOptions.filters),
5859
fixes: {
@@ -74,14 +75,26 @@ export const fillOutRawOptions = ({
7475
ReactPropTypesOptionality.AsWritten,
7576
},
7677
},
77-
include: rawOptions.include ?? compilerOptions.include,
78+
include: rawOptions.include?.length
79+
? rawOptions.include
80+
: parsedTsConfig.fileNames,
7881
mutators: collectAddedMutators(
7982
rawOptions,
8083
packageOptions.directory,
8184
output,
8285
),
8386
output,
8487
package: packageOptions,
88+
parsedTsConfig: {
89+
...parsedTsConfig,
90+
options: {
91+
...parsedTsConfig.options,
92+
noEmit: true,
93+
noImplicitAny,
94+
noImplicitThis,
95+
strictNullChecks: compilerStrictNullChecks,
96+
},
97+
},
8598
postProcess: { shell },
8699
projectPath,
87100
types: {

src/options/loadPendingOptions.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ import { PendingTypeStatOptions, RawTypeStatOptions } from "./types.js";
1212
* Reads pre-file-rename TypeStat options using a config path.
1313
* @returns Promise for filled-out TypeStat options, or a string complaint from failing to make them.
1414
*/
15-
export const loadPendingOptions = async (
15+
export const loadPendingOptions = (
1616
configPath: string | undefined,
17+
cwd: string,
1718
output: ProcessOutput,
18-
): Promise<PendingTypeStatOptions[] | string> => {
19+
): PendingTypeStatOptions[] | string => {
1920
if (configPath === undefined) {
2021
return "-c/--config file must be provided.";
2122
}
2223

23-
const cwd = process.cwd();
2424
const foundRawOptions = findRawOptions(cwd, configPath);
2525
if (typeof foundRawOptions === "string") {
2626
return foundRawOptions;
@@ -34,12 +34,12 @@ export const loadPendingOptions = async (
3434
for (let i = 0; i < allRawOptions.length; i += 1) {
3535
const rawOptions = allRawOptions[i];
3636
const projectPath = getProjectPath(cwd, filePath, rawOptions);
37-
const compilerOptions = await parseRawCompilerOptions(cwd, projectPath);
37+
const parsedTsConfig = parseRawCompilerOptions(cwd, projectPath);
3838

3939
const filledOutOptions = fillOutRawOptions({
40-
compilerOptions,
4140
cwd,
4241
output,
42+
parsedTsConfig,
4343
projectPath,
4444
rawOptions,
4545
});
Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,28 @@
1-
import * as fsp from "node:fs/promises";
1+
import path from "node:path";
22
import ts from "typescript";
33

44
import { createParseConfigHost } from "../services/createParseConfigHost.js";
55
import { stringifyDiagnosticMessageText } from "../shared/diagnostics.js";
66

7-
export interface ParsedCompilerOptions extends ts.CompilerOptions {
8-
include?: string[];
9-
}
10-
11-
export const parseRawCompilerOptions = async (
7+
export const parseRawCompilerOptions = (
128
cwd: string,
139
projectPath: string,
14-
): Promise<ts.CompilerOptions> => {
15-
const configRaw = (await fsp.readFile(projectPath)).toString();
16-
const compilerOptions = ts.parseConfigFileTextToJson(projectPath, configRaw);
17-
if (compilerOptions.error !== undefined) {
10+
): ts.ParsedCommandLine => {
11+
const configFile = ts.getParsedCommandLineOfConfigFile(
12+
path.resolve(cwd, projectPath),
13+
undefined,
14+
createParseConfigHost(cwd),
15+
);
16+
17+
if (!configFile) {
18+
throw new Error("tsConfig file not found.");
19+
}
20+
21+
if (configFile.errors.length) {
1822
throw new Error(
19-
`Could not parse compiler options from '${projectPath}': ${stringifyDiagnosticMessageText(compilerOptions.error)}`,
23+
`Could not parse compiler options from '${projectPath}': ${stringifyDiagnosticMessageText(configFile.errors[0])}`,
2024
);
2125
}
2226

23-
const config = compilerOptions.config as ParsedCompilerOptions;
24-
25-
// TSConfig includes often come in a glob form like ["src"]
26-
config.include &&= ts.parseJsonConfigFileContent(
27-
compilerOptions.config,
28-
createParseConfigHost(),
29-
cwd,
30-
).fileNames;
31-
32-
return config;
27+
return configFile;
3328
};

0 commit comments

Comments
 (0)