Skip to content

Commit aac5ef9

Browse files
jeremyyapJosh Goldberg
authored and
Josh Goldberg
committed
Add align rule converter + indent merger (#248)
* Add converter for align rule * Add merger for indent rule
1 parent 325789d commit aac5ef9

File tree

6 files changed

+266
-0
lines changed

6 files changed

+266
-0
lines changed

src/rules/converters.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { convertAdjacentOverloadSignatures } from "./converters/adjacent-overload-signatures";
2+
import { convertAlign } from "./converters/align";
23
import { convertArrayType } from "./converters/array-type";
34
import { convertArrowParens } from "./converters/arrow-parens";
45
import { convertArrowReturnShorthand } from "./converters/arrow-return-shorthand";
@@ -131,6 +132,7 @@ import { convertVariableName } from "./converters/variable-name";
131132
*/
132133
export const converters = new Map([
133134
["adjacent-overload-signatures", convertAdjacentOverloadSignatures],
135+
["align", convertAlign],
134136
["array-type", convertArrayType],
135137
["arrow-parens", convertArrowParens],
136138
["arrow-return-shorthand", convertArrowReturnShorthand],

src/rules/converters/align.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { RuleConverter } from "../converter";
2+
3+
export const convertAlign: RuleConverter = tslintRule => {
4+
const alignArguments = tslintRule.ruleArguments.includes("arguments");
5+
const alignElements = tslintRule.ruleArguments.includes("elements");
6+
const alignMembers = tslintRule.ruleArguments.includes("members");
7+
const alignParameters = tslintRule.ruleArguments.includes("parameters");
8+
// "statements" alignment is enforced by base indent rule
9+
10+
const objectOption = {
11+
...(alignArguments && {
12+
CallExpression: { arguments: "first" },
13+
}),
14+
...(alignElements && {
15+
ArrayExpression: "first",
16+
}),
17+
...(alignMembers && {
18+
ObjectExpression: "first",
19+
}),
20+
...(alignParameters && {
21+
FunctionDeclaration: { parameters: "first" },
22+
FunctionExpression: { parameters: "first" },
23+
}),
24+
};
25+
26+
// TSLint's "align" rule doesn't care about indent size but "indent" rule requires
27+
// specifying the indent size before the object option. Use the default value of 4.
28+
const ruleArguments = tslintRule.ruleArguments.length === 0 ? undefined : [4, objectOption];
29+
30+
return {
31+
rules: [
32+
{
33+
ruleName: "@typescript-eslint/indent",
34+
...{ ruleArguments },
35+
},
36+
],
37+
};
38+
};
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { convertAlign } from "../align";
2+
3+
describe(convertAlign, () => {
4+
test("conversion without arguments", () => {
5+
const result = convertAlign({
6+
ruleArguments: [],
7+
});
8+
9+
expect(result).toEqual({
10+
rules: [
11+
{
12+
ruleName: "@typescript-eslint/indent",
13+
},
14+
],
15+
});
16+
});
17+
18+
test("conversion with align arguments", () => {
19+
const result = convertAlign({
20+
ruleArguments: ["arguments"],
21+
});
22+
23+
expect(result).toEqual({
24+
rules: [
25+
{
26+
ruleName: "@typescript-eslint/indent",
27+
ruleArguments: [
28+
4,
29+
{
30+
CallExpression: { arguments: "first" },
31+
},
32+
],
33+
},
34+
],
35+
});
36+
});
37+
38+
test("conversion with align elements", () => {
39+
const result = convertAlign({
40+
ruleArguments: ["elements"],
41+
});
42+
43+
expect(result).toEqual({
44+
rules: [
45+
{
46+
ruleName: "@typescript-eslint/indent",
47+
ruleArguments: [
48+
4,
49+
{
50+
ArrayExpression: "first",
51+
},
52+
],
53+
},
54+
],
55+
});
56+
});
57+
58+
test("conversion with align members", () => {
59+
const result = convertAlign({
60+
ruleArguments: ["members"],
61+
});
62+
63+
expect(result).toEqual({
64+
rules: [
65+
{
66+
ruleName: "@typescript-eslint/indent",
67+
ruleArguments: [
68+
4,
69+
{
70+
ObjectExpression: "first",
71+
},
72+
],
73+
},
74+
],
75+
});
76+
});
77+
78+
test("conversion with align parameters", () => {
79+
const result = convertAlign({
80+
ruleArguments: ["parameters"],
81+
});
82+
83+
expect(result).toEqual({
84+
rules: [
85+
{
86+
ruleName: "@typescript-eslint/indent",
87+
ruleArguments: [
88+
4,
89+
{
90+
FunctionDeclaration: { parameters: "first" },
91+
FunctionExpression: { parameters: "first" },
92+
},
93+
],
94+
},
95+
],
96+
});
97+
});
98+
99+
test("conversion with align all", () => {
100+
const result = convertAlign({
101+
ruleArguments: ["parameters", "elements", "arguments", "members"],
102+
});
103+
104+
expect(result).toEqual({
105+
rules: [
106+
{
107+
ruleName: "@typescript-eslint/indent",
108+
ruleArguments: [
109+
4,
110+
{
111+
ArrayExpression: "first",
112+
CallExpression: { arguments: "first" },
113+
FunctionDeclaration: { parameters: "first" },
114+
FunctionExpression: { parameters: "first" },
115+
ObjectExpression: "first",
116+
},
117+
],
118+
},
119+
],
120+
});
121+
});
122+
});

src/rules/mergers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { mergeBanTypes } from "./mergers/ban-types";
2+
import { mergeIndent } from "./mergers/indent";
23
import { mergeNoCaller } from "./mergers/no-caller";
34
import { mergeNoEval } from "./mergers/no-eval";
45
import { mergeNoUnnecessaryTypeAssertion } from "./mergers/no-unnecessary-type-assertion";
56

67
export const mergers = new Map([
78
["@typescript-eslint/ban-types", mergeBanTypes],
9+
["@typescript-eslint/indent", mergeIndent],
810
["@typescript-eslint/no-unnecessary-type-assertion", mergeNoUnnecessaryTypeAssertion],
911
["no-caller", mergeNoCaller],
1012
["no-eval", mergeNoEval],

src/rules/mergers/indent.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { RuleMerger } from "../merger";
2+
3+
const ESLINT_INDENT_DEFAULT = 4;
4+
5+
export const mergeIndent: RuleMerger = (existingOptions, newOptions) => {
6+
if (existingOptions === undefined && newOptions === undefined) {
7+
return [];
8+
}
9+
10+
// Resolve indent size
11+
let indentSize = ESLINT_INDENT_DEFAULT; // default
12+
for (const options of [existingOptions, newOptions]) {
13+
if (
14+
options === undefined ||
15+
options.length === 0 ||
16+
options[0] === ESLINT_INDENT_DEFAULT // ignore default
17+
) {
18+
continue;
19+
}
20+
indentSize = options[0];
21+
}
22+
23+
// Resolve object option
24+
let objectOption = null;
25+
for (const options of [existingOptions, newOptions]) {
26+
if (options === undefined || options.length < 2 || options[1] === undefined) {
27+
continue;
28+
}
29+
objectOption = {
30+
...(objectOption || {}),
31+
...options[1],
32+
};
33+
}
34+
35+
if (indentSize === ESLINT_INDENT_DEFAULT && objectOption === null) {
36+
return [];
37+
} else if (objectOption === null) {
38+
return [indentSize];
39+
}
40+
41+
return [indentSize, objectOption];
42+
};
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { mergeIndent } from "../indent";
2+
3+
describe(mergeIndent, () => {
4+
test("neither options existing", () => {
5+
const result = mergeIndent(undefined, undefined);
6+
7+
expect(result).toEqual([]);
8+
});
9+
10+
test("original indent size existing", () => {
11+
const result = mergeIndent([2], undefined);
12+
13+
expect(result).toEqual([2]);
14+
});
15+
16+
test("new indent size existing", () => {
17+
const result = mergeIndent(undefined, [2]);
18+
19+
expect(result).toEqual([2]);
20+
});
21+
22+
test("both indent sizes existing", () => {
23+
const result = mergeIndent([1], [2]);
24+
25+
expect(result).toEqual([2]);
26+
});
27+
28+
test("default indent sizes existing", () => {
29+
const result = mergeIndent([4], [4]);
30+
31+
expect(result).toEqual([]);
32+
});
33+
34+
test("original object option existing", () => {
35+
const result = mergeIndent([4, { ArrayExpression: "first" }], [2]);
36+
37+
expect(result).toEqual([2, { ArrayExpression: "first" }]);
38+
});
39+
40+
test("new object option existing", () => {
41+
const result = mergeIndent([2], [4, { ArrayExpression: "first" }]);
42+
43+
expect(result).toEqual([2, { ArrayExpression: "first" }]);
44+
});
45+
46+
test("both object option existing", () => {
47+
const result = mergeIndent(
48+
[4, { ObjectExpression: "first" }],
49+
[4, { ArrayExpression: "first" }],
50+
);
51+
52+
expect(result).toEqual([
53+
4,
54+
{
55+
ArrayExpression: "first",
56+
ObjectExpression: "first",
57+
},
58+
]);
59+
});
60+
});

0 commit comments

Comments
 (0)