1
- import type { ASTNode , RuleModule , Token , Tree } from '#types'
1
+ import type { ASTNode , Token , Tree } from '#types'
2
2
import type { MessageIds , RuleOptions } from './types._ts_'
3
- import { castRuleModule , createRule } from '#utils/create-rule'
3
+ import { createRule } from '#utils/create-rule'
4
4
import { AST_NODE_TYPES , AST_TOKEN_TYPES } from '@typescript-eslint/utils'
5
5
import { isNotOpeningParenToken } from '@typescript-eslint/utils/ast-utils'
6
- import _baseRule from './space-infix-ops._js_'
7
-
8
- const baseRule = /* @__PURE__ */ castRuleModule ( _baseRule )
9
6
10
7
const UNIONS = [ '|' , '&' ]
11
8
@@ -17,8 +14,7 @@ export default createRule<RuleOptions, MessageIds>({
17
14
docs : {
18
15
description : 'Require spacing around infix operators' ,
19
16
} ,
20
- fixable : baseRule . meta . fixable ,
21
- hasSuggestions : baseRule . meta . hasSuggestions ,
17
+ fixable : 'whitespace' ,
22
18
schema : [
23
19
{
24
20
type : 'object' ,
@@ -35,7 +31,9 @@ export default createRule<RuleOptions, MessageIds>({
35
31
additionalProperties : false ,
36
32
} ,
37
33
] ,
38
- messages : baseRule . meta . messages ,
34
+ messages : {
35
+ missingSpace : 'Operator \'{{operator}}\' must be spaced.' ,
36
+ } ,
39
37
} ,
40
38
defaultOptions : [
41
39
{
@@ -44,8 +42,8 @@ export default createRule<RuleOptions, MessageIds>({
44
42
} ,
45
43
] ,
46
44
create ( context ) {
45
+ const int32Hint = context . options [ 0 ] ? context . options [ 0 ] . int32Hint === true : false
47
46
const ignoreTypes = context . options [ 0 ] ? context . options [ 0 ] . ignoreTypes === true : false
48
- const rules = ( baseRule as any as RuleModule < any , any > ) . create ( context )
49
47
const sourceCode = context . sourceCode
50
48
51
49
function report ( node : ASTNode , operator : Token ) : void {
@@ -74,6 +72,84 @@ export default createRule<RuleOptions, MessageIds>({
74
72
} )
75
73
}
76
74
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
+
77
153
function isSpaceChar ( token : Token ) : boolean {
78
154
return (
79
155
token . type === AST_TOKEN_TYPES . Punctuator && / ^ [ = ? : ] $ / . test ( token . value )
@@ -181,7 +257,12 @@ export default createRule<RuleOptions, MessageIds>({
181
257
}
182
258
183
259
return {
184
- ...rules ,
260
+ AssignmentExpression : checkBinary ,
261
+ AssignmentPattern : checkBinary ,
262
+ BinaryExpression : checkBinary ,
263
+ LogicalExpression : checkBinary ,
264
+ ConditionalExpression : checkConditional ,
265
+ VariableDeclarator : checkVar ,
185
266
TSEnumMember : checkForEnumAssignmentSpace ,
186
267
PropertyDefinition : checkForPropertyDefinitionAssignmentSpace ,
187
268
TSTypeAliasDeclaration : checkForTypeAliasAssignment ,
0 commit comments