Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 343d20d

Browse files
authored
feat(eslint-plugin): add extension rule space-infix-ops (typescript-eslint#2593)
1 parent e012049 commit 343d20d

File tree

7 files changed

+257
-0
lines changed

7 files changed

+257
-0
lines changed

packages/eslint-plugin/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ In these cases, we create what we call an extension rule; a rule within our plug
219219
| [`@typescript-eslint/return-await`](./docs/rules/return-await.md) | Enforces consistent returning of awaited values | | :wrench: | :thought_balloon: |
220220
| [`@typescript-eslint/semi`](./docs/rules/semi.md) | Require or disallow semicolons instead of ASI | | :wrench: | |
221221
| [`@typescript-eslint/space-before-function-paren`](./docs/rules/space-before-function-paren.md) | Enforces consistent spacing before function parenthesis | | :wrench: | |
222+
| [`@typescript-eslint/space-infix-ops`](./docs/rules/space-infix-ops.md) | This rule is aimed at ensuring there are spaces around infix operators. | | :wrench: | |
222223

223224
<!-- end extension rule list -->
224225

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# This rule is aimed at ensuring there are spaces around infix operators. (`space-infix-ops`)
2+
3+
This rule extends the base [`eslint/space-infix-ops`](https://eslint.org/docs/rules/space-infix-ops) rule.
4+
5+
It also add support for enum members
6+
7+
```ts
8+
enum MyEnum {
9+
KEY = 'value',
10+
}
11+
```
12+
13+
## How to use
14+
15+
```jsonc
16+
{
17+
"space-infix-ops": "off",
18+
"@typescript-eslint/space-infix-ops": ["error", { "int32Hint": false }]
19+
}
20+
```
21+
22+
## Options
23+
24+
See [`eslint/space-infix-ops` options](https://eslint.org/docs/rules/space-infix-ops#options).
25+
26+
<sup>Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/space-infix-ops.md)</sup>

packages/eslint-plugin/src/configs/all.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ export = {
137137
'@typescript-eslint/semi': 'error',
138138
'space-before-function-paren': 'off',
139139
'@typescript-eslint/space-before-function-paren': 'error',
140+
'space-infix-ops': 'off',
141+
'@typescript-eslint/space-infix-ops': 'error',
140142
'@typescript-eslint/strict-boolean-expressions': 'error',
141143
'@typescript-eslint/switch-exhaustiveness-check': 'error',
142144
'@typescript-eslint/triple-slash-reference': 'error',

packages/eslint-plugin/src/rules/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import consistentTypeDefinitions from './consistent-type-definitions';
1515
import consistentTypeImports from './consistent-type-imports';
1616
import defaultParamLast from './default-param-last';
1717
import dotNotation from './dot-notation';
18+
import enumMembersSpacing from './space-infix-ops';
1819
import explicitFunctionReturnType from './explicit-function-return-type';
1920
import explicitMemberAccessibility from './explicit-member-accessibility';
2021
import explicitModuleBoundaryTypes from './explicit-module-boundary-types';
@@ -125,6 +126,7 @@ export default {
125126
'consistent-type-imports': consistentTypeImports,
126127
'default-param-last': defaultParamLast,
127128
'dot-notation': dotNotation,
129+
'space-infix-ops': enumMembersSpacing,
128130
'explicit-function-return-type': explicitFunctionReturnType,
129131
'explicit-member-accessibility': explicitMemberAccessibility,
130132
'explicit-module-boundary-types': explicitModuleBoundaryTypes,
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import {
2+
AST_TOKEN_TYPES,
3+
TSESTree,
4+
} from '@typescript-eslint/experimental-utils';
5+
import baseRule from 'eslint/lib/rules/space-infix-ops';
6+
import * as util from '../util';
7+
8+
export type Options = util.InferOptionsTypeFromRule<typeof baseRule>;
9+
export type MessageIds = util.InferMessageIdsTypeFromRule<typeof baseRule>;
10+
11+
export default util.createRule<Options, MessageIds>({
12+
name: 'space-infix-ops',
13+
meta: {
14+
type: 'layout',
15+
docs: {
16+
description:
17+
'This rule is aimed at ensuring there are spaces around infix operators.',
18+
category: 'Stylistic Issues',
19+
recommended: false,
20+
extendsBaseRule: true,
21+
},
22+
fixable: baseRule.meta.fixable,
23+
schema: baseRule.meta.schema,
24+
messages: baseRule.meta.messages ?? {
25+
missingSpace: "Operator '{{operator}}' must be spaced.",
26+
},
27+
},
28+
defaultOptions: [
29+
{
30+
int32Hint: false,
31+
},
32+
],
33+
create(context) {
34+
const rules = baseRule.create(context);
35+
const sourceCode = context.getSourceCode();
36+
37+
/**
38+
* Check if it has an assignment char and report if it's faulty
39+
* @param node The node to report
40+
*/
41+
function checkForAssignmentSpace(node: TSESTree.TSEnumMember): void {
42+
if (!node.initializer) {
43+
return;
44+
}
45+
46+
const leftNode = sourceCode.getTokenByRangeStart(node.id.range[0])!;
47+
const rightNode = sourceCode.getTokenByRangeStart(
48+
node.initializer.range[0],
49+
)!;
50+
51+
if (!rightNode) {
52+
return;
53+
}
54+
55+
const operator = sourceCode.getFirstTokenBetween(
56+
leftNode,
57+
rightNode,
58+
token =>
59+
token.type === AST_TOKEN_TYPES.Punctuator && token.value === '=',
60+
);
61+
const prev = sourceCode.getTokenBefore(operator!);
62+
const next = sourceCode.getTokenAfter(operator!);
63+
64+
if (
65+
operator &&
66+
(!sourceCode.isSpaceBetweenTokens(prev!, operator) ||
67+
!sourceCode.isSpaceBetweenTokens(operator, next!))
68+
) {
69+
context.report({
70+
node: node,
71+
loc: operator.loc,
72+
messageId: 'missingSpace',
73+
data: {
74+
operator: operator.value,
75+
},
76+
fix(fixer) {
77+
const previousToken = sourceCode.getTokenBefore(operator);
78+
const afterToken = sourceCode.getTokenAfter(operator);
79+
let fixString = '';
80+
81+
if (operator.range[0] - previousToken!.range[1] === 0) {
82+
fixString = ' ';
83+
}
84+
85+
fixString += operator.value;
86+
87+
if (afterToken!.range[0] - operator.range[1] === 0) {
88+
fixString += ' ';
89+
}
90+
91+
return fixer.replaceText(operator, fixString);
92+
},
93+
});
94+
}
95+
}
96+
97+
return {
98+
...rules,
99+
TSEnumMember: checkForAssignmentSpace,
100+
};
101+
},
102+
});
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/* eslint-disable eslint-comments/no-use */
2+
// this rule tests spacing, which prettier will want to fix and break the tests
3+
/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */
4+
/* eslint-enable eslint-comments/no-use */
5+
6+
import rule from '../../src/rules/space-infix-ops';
7+
import { RuleTester } from '../RuleTester';
8+
9+
const ruleTester = new RuleTester({
10+
parser: '@typescript-eslint/parser',
11+
});
12+
13+
ruleTester.run('space-infix-ops', rule, {
14+
valid: [
15+
{
16+
code: `
17+
enum Test {
18+
KEY1 = 2,
19+
}
20+
`,
21+
},
22+
{
23+
code: `
24+
enum Test {
25+
KEY1 = "value",
26+
}
27+
`,
28+
},
29+
{
30+
code: `
31+
enum Test {
32+
KEY1,
33+
}
34+
`,
35+
},
36+
],
37+
invalid: [
38+
{
39+
code: `
40+
enum Test {
41+
A= 2,
42+
B = 1,
43+
}
44+
`,
45+
output: `
46+
enum Test {
47+
A = 2,
48+
B = 1,
49+
}
50+
`,
51+
errors: [
52+
{
53+
messageId: 'missingSpace',
54+
column: 12,
55+
line: 3,
56+
},
57+
],
58+
},
59+
{
60+
code: `
61+
enum Test {
62+
KEY1= "value1",
63+
KEY2 = "value2",
64+
}
65+
`,
66+
output: `
67+
enum Test {
68+
KEY1 = "value1",
69+
KEY2 = "value2",
70+
}
71+
`,
72+
errors: [
73+
{
74+
messageId: 'missingSpace',
75+
column: 15,
76+
line: 3,
77+
},
78+
],
79+
},
80+
{
81+
code: `
82+
enum Test {
83+
A =2,
84+
B = 1,
85+
}
86+
`,
87+
output: `
88+
enum Test {
89+
A = 2,
90+
B = 1,
91+
}
92+
`,
93+
errors: [
94+
{
95+
messageId: 'missingSpace',
96+
column: 13,
97+
line: 3,
98+
},
99+
],
100+
},
101+
],
102+
});

packages/eslint-plugin/typings/eslint-rules.d.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,3 +789,25 @@ declare module 'eslint/lib/rules/no-duplicate-imports' {
789789
>;
790790
export = rule;
791791
}
792+
793+
declare module 'eslint/lib/rules/space-infix-ops' {
794+
import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';
795+
796+
const rule: TSESLint.RuleModule<
797+
'missingSpace',
798+
[
799+
{
800+
int32Hint: boolean;
801+
},
802+
],
803+
{
804+
AssignmentExpression(node: TSESTree.AssignmentExpression): void;
805+
AssignmentPattern(node: TSESTree.AssignmentPattern): void;
806+
BinaryExpression(node: TSESTree.BinaryExpression): void;
807+
LogicalExpression(node: TSESTree.LogicalExpression): void;
808+
ConditionalExpression(node: TSESTree.ConditionalExpression): void;
809+
VariableDeclarator(node: TSESTree.VariableDeclarator): void;
810+
}
811+
>;
812+
export = rule;
813+
}

0 commit comments

Comments
 (0)