Skip to content

Commit 4ffb50c

Browse files
authored
improve type safety with regards to config files (#601)
* improve type safety with regards to config files * removing type test + cleaning up test description
1 parent 8325578 commit 4ffb50c

11 files changed

+87
-58
lines changed

src/creation/eslint/createEnv.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,20 @@ describe("createEnv", () => {
6363
});
6464
});
6565

66+
it("handles an environment where typescript configuration files are mostly undefined", () => {
67+
// Arrange
68+
const packages = undefined;
69+
const typescript = {};
70+
71+
// Act
72+
const env = createEnv({ packages, typescript });
73+
74+
// Assert
75+
expect(env).not.toContain({
76+
browser: expect.any(Boolean),
77+
});
78+
});
79+
6680
it("returns browser as true if a typescript lib is dom", () => {
6781
// Arrange
6882
const packages = undefined;

src/creation/eslint/createEnv.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ export const createEnv = ({
66
}: Pick<AllOriginalConfigurations, "packages" | "typescript">) => {
77
const browser =
88
typescript === undefined ||
9-
typescript.compilerOptions.lib === undefined ||
9+
typescript.compilerOptions?.lib === undefined ||
1010
typescript.compilerOptions.lib.includes("dom");
1111

1212
const es6 =
1313
typescript === undefined ||
14-
!["es3", "es5"].includes(typescript.compilerOptions.target.toLowerCase());
14+
!["es3", "es5"].includes(typescript.compilerOptions?.target?.toLowerCase() ?? "");
1515

1616
const node =
1717
packages === undefined ||

src/input/findESLintConfiguration.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import { OriginalConfigurations } from "./findOriginalConfigurations";
99
import { importer } from "./importer";
1010

1111
export type ESLintConfiguration = {
12-
env: Record<string, boolean>;
13-
extends: string | string[];
14-
globals?: Record<string, boolean>;
15-
rules: ESLintConfigurationRules;
12+
env?: Record<string, boolean | undefined>;
13+
extends?: string | string[];
14+
globals?: Record<string, boolean | undefined>;
15+
rules?: ESLintConfigurationRules;
1616
};
1717

1818
export type ESLintConfigurationRules = {
@@ -43,7 +43,7 @@ export const findESLintConfiguration = async (
4343
findRawConfiguration<ESLintConfiguration>(dependencies.importer, filePath, {
4444
extends: [],
4545
}),
46-
findReportedConfiguration<Partial<ESLintConfiguration>>(
46+
findReportedConfiguration<ESLintConfiguration>(
4747
dependencies.exec,
4848
"eslint --print-config",
4949
filePath,

src/input/findOriginalConfigurations.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from "./findTypeScriptConfiguration";
1515
import { findTSLintConfiguration, TSLintConfiguration } from "./findTSLintConfiguration";
1616
import { mergeLintConfigurations } from "./mergeLintConfigurations";
17+
import { DeepPartial } from "./findReportedConfiguration";
1718

1819
export type FindOriginalConfigurationsDependencies = {
1920
findESLintConfiguration: SansDependencies<typeof findESLintConfiguration>;
@@ -35,7 +36,7 @@ export type OriginalConfigurations<Configuration> = {
3536
/**
3637
* Raw import results from `import`ing the configuration file.
3738
*/
38-
raw: Partial<Configuration>;
39+
raw: DeepPartial<Configuration>;
3940
};
4041

4142
export type AllOriginalConfigurations = {

src/input/findPackagesConfiguration.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import {
44
} from "./findReportedConfiguration";
55

66
export type PackagesConfiguration = {
7-
dependencies: Record<string, string>;
8-
devDependencies: Record<string, string>;
7+
dependencies: Record<string, string | undefined>;
8+
devDependencies: Record<string, string | undefined>;
99
};
1010

1111
export const findPackagesConfiguration = async (

src/input/findReportedConfiguration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Exec } from "../adapters/exec";
22

33
export type DeepPartial<T> = {
4-
[P in keyof T]?: T[P] extends Record<P, T[P]> ? DeepPartial<T[P]> : T[P];
4+
[P in keyof T]?: T[P] extends Record<string, unknown> ? DeepPartial<T[P]> : T[P];
55
};
66

77
export type FindReportedConfigurationDependencies = {

src/input/findTSLintConfiguration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { importer } from "./importer";
88
export type TSLintConfiguration = {
99
extends?: string[];
1010
rulesDirectory?: string[];
11-
rules: TSLintConfigurationRules;
11+
rules?: TSLintConfigurationRules;
1212
};
1313

1414
export type TSLintConfigurationRules = Record<string, any>;

src/input/findTypeScriptConfiguration.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import {
44
} from "./findReportedConfiguration";
55

66
export type TypeScriptConfiguration = {
7-
compilerOptions: {
7+
compilerOptions?: {
88
lib?: string[];
9-
target: string;
9+
target?: string;
1010
};
1111
};
1212

src/input/mergeLintConfigurations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const mergeLintConfigurations = (
1010
return tslint;
1111
}
1212

13-
const mappedConfig = eslint.full.rules["@typescript-eslint/tslint/config"];
13+
const mappedConfig = eslint.full.rules?.["@typescript-eslint/tslint/config"];
1414
if (!(mappedConfig instanceof Array) || mappedConfig[0] === "off") {
1515
return tslint;
1616
}

src/rules/convertRules.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ import { RuleConverter, ConversionResult } from "./converter";
55
import { RuleMerger } from "./merger";
66

77
describe("convertRules", () => {
8+
it("doesn't crash when passed an undefined configuration", () => {
9+
// Arrange
10+
const { converters, mergers } = setupConversionEnvironment({
11+
ruleSeverity: "off",
12+
});
13+
14+
// Act
15+
const { missing } = convertRules({ converters, mergers }, undefined);
16+
17+
// Assert
18+
expect(missing).toEqual([]);
19+
});
20+
821
it("doesn't marks a disabled rule as missing when its converter returns undefined", () => {
922
// Arrange
1023
const { tslintRule, converters, mergers } = setupConversionEnvironment({

src/rules/convertRules.ts

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -22,66 +22,67 @@ export type RuleConversionResults = {
2222

2323
export const convertRules = (
2424
dependencies: ConvertRulesDependencies,
25-
rawTslintRules: TSLintConfigurationRules,
25+
rawTslintRules?: TSLintConfigurationRules,
2626
): RuleConversionResults => {
2727
const converted = new Map<string, ESLintRuleOptions>();
2828
const failed: ConversionError[] = [];
2929
const missing: TSLintRuleOptions[] = [];
3030
const plugins = new Set<string>();
3131

32-
for (const [ruleName, value] of Object.entries(rawTslintRules)) {
33-
const tslintRule = formatRawTslintRule(ruleName, value);
34-
const conversion = convertRule(tslintRule, dependencies.converters);
32+
if (rawTslintRules !== undefined) {
33+
for (const [ruleName, value] of Object.entries(rawTslintRules)) {
34+
const tslintRule = formatRawTslintRule(ruleName, value);
35+
const conversion = convertRule(tslintRule, dependencies.converters);
3536

36-
if (conversion === undefined) {
37-
if (tslintRule.ruleSeverity !== "off") {
38-
missing.push(tslintRule);
39-
}
40-
41-
continue;
42-
}
37+
if (conversion === undefined) {
38+
if (tslintRule.ruleSeverity !== "off") {
39+
missing.push(tslintRule);
40+
}
4341

44-
if (conversion instanceof ConversionError) {
45-
failed.push(conversion);
46-
continue;
47-
}
48-
49-
for (const changes of conversion.rules) {
50-
const existingConversion = converted.get(changes.ruleName);
51-
const newConversion = {
52-
...changes,
53-
ruleSeverity: convertTSLintRuleSeverity(tslintRule.ruleSeverity),
54-
};
42+
continue;
43+
}
5544

56-
if (existingConversion === undefined) {
57-
converted.set(changes.ruleName, newConversion);
45+
if (conversion instanceof ConversionError) {
46+
failed.push(conversion);
5847
continue;
5948
}
6049

61-
const merger = dependencies.mergers.get(changes.ruleName);
62-
if (merger === undefined) {
63-
failed.push(ConversionError.forMerger(changes.ruleName));
64-
} else {
65-
const existingNotices = existingConversion.notices ?? [];
66-
const newNotices = newConversion.notices ?? [];
50+
for (const changes of conversion.rules) {
51+
const existingConversion = converted.get(changes.ruleName);
52+
const newConversion = {
53+
...changes,
54+
ruleSeverity: convertTSLintRuleSeverity(tslintRule.ruleSeverity),
55+
};
56+
57+
if (existingConversion === undefined) {
58+
converted.set(changes.ruleName, newConversion);
59+
continue;
60+
}
61+
62+
const merger = dependencies.mergers.get(changes.ruleName);
63+
if (merger === undefined) {
64+
failed.push(ConversionError.forMerger(changes.ruleName));
65+
} else {
66+
const existingNotices = existingConversion.notices ?? [];
67+
const newNotices = newConversion.notices ?? [];
6768

68-
converted.set(changes.ruleName, {
69-
...existingConversion,
70-
ruleArguments: merger(
71-
existingConversion.ruleArguments,
72-
newConversion.ruleArguments,
73-
),
74-
notices: Array.from(new Set([...existingNotices, ...newNotices])),
75-
});
69+
converted.set(changes.ruleName, {
70+
...existingConversion,
71+
ruleArguments: merger(
72+
existingConversion.ruleArguments,
73+
newConversion.ruleArguments,
74+
),
75+
notices: Array.from(new Set([...existingNotices, ...newNotices])),
76+
});
77+
}
7678
}
77-
}
7879

79-
if (conversion.plugins !== undefined) {
80-
for (const newPlugin of conversion.plugins) {
81-
plugins.add(newPlugin);
80+
if (conversion.plugins !== undefined) {
81+
for (const newPlugin of conversion.plugins) {
82+
plugins.add(newPlugin);
83+
}
8284
}
8385
}
8486
}
85-
8687
return { converted, failed, missing, plugins };
8788
};

0 commit comments

Comments
 (0)