1
1
import {
2
+ TSESLint ,
2
3
TSESTree ,
3
4
AST_NODE_TYPES ,
4
5
} from '@typescript-eslint/experimental-utils' ;
@@ -11,6 +12,9 @@ type TypeOptions = {
11
12
delimiter ?: Delimiter ;
12
13
requireLast ?: boolean ;
13
14
} ;
15
+ type TypeOptionsWithType = TypeOptions & {
16
+ type : string ;
17
+ } ;
14
18
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
15
19
type BaseOptions = {
16
20
multiline ?: TypeOptions ;
@@ -29,6 +33,20 @@ type MessageIds =
29
33
| 'unexpectedSemi'
30
34
| 'expectedComma'
31
35
| 'expectedSemi' ;
36
+ type LastTokenType = TSESTree . Token ;
37
+
38
+ interface MakeFixFunctionParams {
39
+ optsNone : boolean ;
40
+ optsSemi : boolean ;
41
+ lastToken : LastTokenType ;
42
+ missingDelimiter : boolean ;
43
+ lastTokenLine : string ;
44
+ isSingleLine : boolean ;
45
+ }
46
+
47
+ type MakeFixFunctionReturnType =
48
+ | ( ( fixer : TSESLint . RuleFixer ) => TSESLint . RuleFix )
49
+ | null ;
32
50
33
51
const definition = {
34
52
type : 'object' ,
@@ -54,6 +72,47 @@ const definition = {
54
72
additionalProperties : false ,
55
73
} ;
56
74
75
+ const isLastTokenEndOfLine = ( token : string , line : string ) : boolean => {
76
+ const positionInLine = line . indexOf ( token ) ;
77
+
78
+ return positionInLine === line . length - 1 ;
79
+ } ;
80
+
81
+ const makeFixFunction = ( {
82
+ optsNone,
83
+ optsSemi,
84
+ lastToken,
85
+ missingDelimiter,
86
+ lastTokenLine,
87
+ isSingleLine,
88
+ } : MakeFixFunctionParams ) : MakeFixFunctionReturnType => {
89
+ // if removing is the action but last token is not the end of the line
90
+ if (
91
+ optsNone &&
92
+ ! isLastTokenEndOfLine ( lastToken . value , lastTokenLine ) &&
93
+ ! isSingleLine
94
+ ) {
95
+ return null ;
96
+ }
97
+
98
+ return ( fixer : TSESLint . RuleFixer ) : TSESLint . RuleFix => {
99
+ if ( optsNone ) {
100
+ // remove the unneeded token
101
+ return fixer . remove ( lastToken ) ;
102
+ }
103
+
104
+ const token = optsSemi ? ';' : ',' ;
105
+
106
+ if ( missingDelimiter ) {
107
+ // add the missing delimiter
108
+ return fixer . insertTextAfter ( lastToken , token ) ;
109
+ }
110
+
111
+ // correct the current delimiter
112
+ return fixer . replaceText ( lastToken , token ) ;
113
+ } ;
114
+ } ;
115
+
57
116
export default util . createRule < Options , MessageIds > ( {
58
117
name : 'member-delimiter-style' ,
59
118
meta : {
@@ -127,7 +186,7 @@ export default util.createRule<Options, MessageIds>({
127
186
*/
128
187
function checkLastToken (
129
188
member : TSESTree . TypeElement ,
130
- opts : TypeOptions ,
189
+ opts : TypeOptionsWithType ,
131
190
isLast : boolean ,
132
191
) : void {
133
192
/**
@@ -147,10 +206,14 @@ export default util.createRule<Options, MessageIds>({
147
206
const lastToken = sourceCode . getLastToken ( member , {
148
207
includeComments : false ,
149
208
} ) ;
209
+
150
210
if ( ! lastToken ) {
151
211
return ;
152
212
}
153
213
214
+ const sourceCodeLines = sourceCode . getLines ( ) ;
215
+ const lastTokenLine = sourceCodeLines [ lastToken ?. loc . start . line - 1 ] ;
216
+
154
217
const optsSemi = getOption ( 'semi' ) ;
155
218
const optsComma = getOption ( 'comma' ) ;
156
219
const optsNone = getOption ( 'none' ) ;
@@ -193,22 +256,14 @@ export default util.createRule<Options, MessageIds>({
193
256
} ,
194
257
} ,
195
258
messageId,
196
- fix ( fixer ) {
197
- if ( optsNone ) {
198
- // remove the unneeded token
199
- return fixer . remove ( lastToken ) ;
200
- }
201
-
202
- const token = optsSemi ? ';' : ',' ;
203
-
204
- if ( missingDelimiter ) {
205
- // add the missing delimiter
206
- return fixer . insertTextAfter ( lastToken , token ) ;
207
- }
208
-
209
- // correct the current delimiter
210
- return fixer . replaceText ( lastToken , token ) ;
211
- } ,
259
+ fix : makeFixFunction ( {
260
+ optsNone,
261
+ optsSemi,
262
+ lastToken,
263
+ missingDelimiter,
264
+ lastTokenLine,
265
+ isSingleLine : opts . type === 'single-line' ,
266
+ } ) ,
212
267
} ) ;
213
268
}
214
269
}
@@ -239,7 +294,9 @@ export default util.createRule<Options, MessageIds>({
239
294
node . type === AST_NODE_TYPES . TSInterfaceBody
240
295
? interfaceOptions
241
296
: typeLiteralOptions ;
242
- const opts = isSingleLine ? typeOpts . singleline : typeOpts . multiline ;
297
+ const opts = isSingleLine
298
+ ? { ...typeOpts . singleline , type : 'single-line' }
299
+ : { ...typeOpts . multiline , type : 'multi-line' } ;
243
300
244
301
members . forEach ( ( member , index ) => {
245
302
checkLastToken ( member , opts ?? { } , index === members . length - 1 ) ;
0 commit comments