Skip to content

Commit 1a1b388

Browse files
authoredFeb 26, 2025··
refactor: merge space-infix-ops (#697)
1 parent 6e8554d commit 1a1b388

File tree

1 file changed

+91
-10
lines changed

1 file changed

+91
-10
lines changed
 

‎packages/eslint-plugin/rules/space-infix-ops/space-infix-ops._ts_.ts

+91-10
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
import type { ASTNode, RuleModule, Token, Tree } from '#types'
1+
import type { ASTNode, Token, Tree } from '#types'
22
import type { MessageIds, RuleOptions } from './types._ts_'
3-
import { castRuleModule, createRule } from '#utils/create-rule'
3+
import { createRule } from '#utils/create-rule'
44
import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'
55
import { isNotOpeningParenToken } from '@typescript-eslint/utils/ast-utils'
6-
import _baseRule from './space-infix-ops._js_'
7-
8-
const baseRule = /* @__PURE__ */ castRuleModule(_baseRule)
96

107
const UNIONS = ['|', '&']
118

@@ -17,8 +14,7 @@ export default createRule<RuleOptions, MessageIds>({
1714
docs: {
1815
description: 'Require spacing around infix operators',
1916
},
20-
fixable: baseRule.meta.fixable,
21-
hasSuggestions: baseRule.meta.hasSuggestions,
17+
fixable: 'whitespace',
2218
schema: [
2319
{
2420
type: 'object',
@@ -35,7 +31,9 @@ export default createRule<RuleOptions, MessageIds>({
3531
additionalProperties: false,
3632
},
3733
],
38-
messages: baseRule.meta.messages,
34+
messages: {
35+
missingSpace: 'Operator \'{{operator}}\' must be spaced.',
36+
},
3937
},
4038
defaultOptions: [
4139
{
@@ -44,8 +42,8 @@ export default createRule<RuleOptions, MessageIds>({
4442
},
4543
],
4644
create(context) {
45+
const int32Hint = context.options[0] ? context.options[0].int32Hint === true : false
4746
const ignoreTypes = context.options[0] ? context.options[0].ignoreTypes === true : false
48-
const rules = (baseRule as any as RuleModule<any, any>).create(context)
4947
const sourceCode = context.sourceCode
5048

5149
function report(node: ASTNode, operator: Token): void {
@@ -74,6 +72,84 @@ export default createRule<RuleOptions, MessageIds>({
7472
})
7573
}
7674

75+
/**
76+
* Returns the first token which violates the rule
77+
* @param left The left node of the main node
78+
* @param right The right node of the main node
79+
* @param op The operator of the main node
80+
* @returns The violator token or null
81+
* @private
82+
*/
83+
function getFirstNonSpacedToken(left: ASTNode, right: ASTNode, op: string) {
84+
const operator = sourceCode.getFirstTokenBetween(left, right, token => token.value === op)!
85+
const prev = sourceCode.getTokenBefore(operator)!
86+
const next = sourceCode.getTokenAfter(operator)!
87+
88+
if (!sourceCode.isSpaceBetween(prev, operator) || !sourceCode.isSpaceBetween(operator, next))
89+
return operator
90+
return null
91+
}
92+
93+
/**
94+
* Check if the node is binary then report
95+
* @param node node to evaluate
96+
* @private
97+
*/
98+
function checkBinary(
99+
node:
100+
| Tree.AssignmentExpression
101+
| Tree.AssignmentPattern
102+
| Tree.BinaryExpression
103+
| Tree.LogicalExpression,
104+
) {
105+
const leftNode = ('typeAnnotation' in node.left && node.left.typeAnnotation)
106+
? node.left.typeAnnotation : node.left
107+
const rightNode = node.right
108+
109+
// search for = in AssignmentPattern nodes
110+
const operator = ('operator' in node && node.operator) ? node.operator : '='
111+
112+
const nonSpacedNode = getFirstNonSpacedToken(leftNode, rightNode, operator)
113+
114+
if (nonSpacedNode) {
115+
if (!(int32Hint && sourceCode.getText(node).endsWith('|0')))
116+
report(node, nonSpacedNode)
117+
}
118+
}
119+
120+
/**
121+
* Check if the node is conditional
122+
* @param node node to evaluate
123+
* @private
124+
*/
125+
function checkConditional(node: Tree.ConditionalExpression) {
126+
const nonSpacedConsequentNode = getFirstNonSpacedToken(node.test, node.consequent, '?')
127+
const nonSpacedAlternateNode = getFirstNonSpacedToken(node.consequent, node.alternate, ':')
128+
129+
if (nonSpacedConsequentNode)
130+
report(node, nonSpacedConsequentNode)
131+
132+
if (nonSpacedAlternateNode)
133+
report(node, nonSpacedAlternateNode)
134+
}
135+
136+
/**
137+
* Check if the node is a variable
138+
* @param node node to evaluate
139+
* @private
140+
*/
141+
function checkVar(node: Tree.VariableDeclarator) {
142+
const leftNode = (node.id.typeAnnotation) ? node.id.typeAnnotation : node.id
143+
const rightNode = node.init
144+
145+
if (rightNode) {
146+
const nonSpacedNode = getFirstNonSpacedToken(leftNode, rightNode, '=')
147+
148+
if (nonSpacedNode)
149+
report(node, nonSpacedNode)
150+
}
151+
}
152+
77153
function isSpaceChar(token: Token): boolean {
78154
return (
79155
token.type === AST_TOKEN_TYPES.Punctuator && /^[=?:]$/.test(token.value)
@@ -181,7 +257,12 @@ export default createRule<RuleOptions, MessageIds>({
181257
}
182258

183259
return {
184-
...rules,
260+
AssignmentExpression: checkBinary,
261+
AssignmentPattern: checkBinary,
262+
BinaryExpression: checkBinary,
263+
LogicalExpression: checkBinary,
264+
ConditionalExpression: checkConditional,
265+
VariableDeclarator: checkVar,
185266
TSEnumMember: checkForEnumAssignmentSpace,
186267
PropertyDefinition: checkForPropertyDefinitionAssignmentSpace,
187268
TSTypeAliasDeclaration: checkForTypeAliasAssignment,

0 commit comments

Comments
 (0)
Please sign in to comment.