99} from "@eslint-community/eslint-utils" ;
1010import type { Rule , AST as ESLintAST , SourceCode } from "eslint" ;
1111import type { AST } from "jsonc-eslint-parser" ;
12+ import type * as ESTree from "estree" ;
1213
1314/**
1415 * Check if the token is a comma.
@@ -55,14 +56,23 @@ export function* fixForSorting(
5556) : IterableIterator < Rule . Fix > {
5657 const targetInfo = calcTargetInfo ( sourceCode , target ) ;
5758
58- const toBeforeToken = to . node
59- ? sourceCode . getTokenBefore ( getFirstTokenOfNode ( sourceCode , to . node ) ) !
60- : to . before ;
61- let insertRange = toBeforeToken . range ;
62- const toBeforeNextToken = sourceCode . getTokenAfter ( toBeforeToken , {
59+ const toPrevInfo = getPrevElementInfo ( sourceCode , to ) ;
60+
61+ if (
62+ toPrevInfo . comma &&
63+ toPrevInfo . last . range ! [ 1 ] <= toPrevInfo . comma . range [ 0 ]
64+ ) {
65+ yield fixer . removeRange ( toPrevInfo . comma . range ) ;
66+ }
67+
68+ let insertRange = [
69+ toPrevInfo . last . range ! [ 1 ] ,
70+ toPrevInfo . last . range ! [ 1 ] ,
71+ ] as ESLintAST . Range ;
72+ const toBeforeNextToken = sourceCode . getTokenAfter ( toPrevInfo . last , {
6373 includeComments : true ,
6474 } ) ! ;
65- if ( toBeforeNextToken . loc ! . start . line - toBeforeToken . loc . end . line > 1 ) {
75+ if ( toBeforeNextToken . loc ! . start . line - toPrevInfo . last . loc ! . end . line > 1 ) {
6676 // If there are blank lines, the element is inserted after the blank lines.
6777 const offset = sourceCode . getIndexFromLoc ( {
6878 line : toBeforeNextToken . loc ! . start . line - 1 ,
@@ -94,35 +104,41 @@ function calcTargetInfo(
94104 const nodeLastToken = getLastTokenOfNode ( sourceCode , node ) ;
95105
96106 const endInfo = getElementEndInfo ( sourceCode , node ) ;
97- const prevInfo = getPrevElementInfo ( sourceCode , node ) ;
107+ const prevInfo = getPrevElementInfo ( sourceCode , { node } ) ;
98108
99109 let insertCode : string ;
100110
101111 const removeRanges : ESLintAST . Range [ ] = [ ] ;
102- if ( prevInfo . comma && prevInfo . end <= prevInfo . comma . range [ 0 ] ) {
112+ if ( prevInfo . comma && prevInfo . last . range ! [ 1 ] <= prevInfo . comma . range [ 0 ] ) {
103113 insertCode = `${ sourceCode . text . slice (
104- prevInfo . end ,
114+ prevInfo . last . range ! [ 1 ] ,
105115 prevInfo . comma . range [ 0 ] ,
106116 ) } ${ sourceCode . text . slice ( prevInfo . comma . range [ 1 ] , nodeLastToken . range [ 1 ] ) } `;
107117 removeRanges . push (
108- [ prevInfo . end , prevInfo . comma . range [ 0 ] ] ,
118+ [ prevInfo . last . range ! [ 1 ] , prevInfo . comma . range [ 0 ] ] ,
109119 [ prevInfo . comma . range [ 1 ] , nodeLastToken . range [ 1 ] ] ,
110120 ) ;
111121 } else {
112- insertCode = sourceCode . text . slice ( prevInfo . end , nodeLastToken . range [ 1 ] ) ;
113- removeRanges . push ( [ prevInfo . end , nodeLastToken . range [ 1 ] ] ) ;
122+ insertCode = sourceCode . text . slice (
123+ prevInfo . last . range ! [ 1 ] ,
124+ nodeLastToken . range [ 1 ] ,
125+ ) ;
126+ removeRanges . push ( [ prevInfo . last . range ! [ 1 ] , nodeLastToken . range [ 1 ] ] ) ;
114127 }
115128
116129 const hasTrailingComma =
117- endInfo . comma && endInfo . comma . range [ 1 ] <= endInfo . end ;
130+ endInfo . comma && endInfo . comma . range [ 1 ] <= endInfo . last . range ! [ 1 ] ;
118131 if ( ! hasTrailingComma ) {
119132 insertCode += "," ;
120133 if ( prevInfo . comma ) {
121134 removeRanges . push ( prevInfo . comma . range ) ;
122135 }
123136 }
124- insertCode += sourceCode . text . slice ( nodeLastToken . range [ 1 ] , endInfo . end ) ;
125- removeRanges . push ( [ nodeLastToken . range [ 1 ] , endInfo . end ] ) ;
137+ insertCode += sourceCode . text . slice (
138+ nodeLastToken . range [ 1 ] ,
139+ endInfo . last . range ! [ 1 ] ,
140+ ) ;
141+ removeRanges . push ( [ nodeLastToken . range [ 1 ] , endInfo . last . range ! [ 1 ] ] ) ;
126142
127143 return {
128144 insertCode,
@@ -214,8 +230,8 @@ function getElementEndInfo(
214230 comma : ESLintAST . Token | null ;
215231 // Next element token
216232 nextElement : ESLintAST . Token | null ;
217- // The end of the range of the target element
218- end : number ;
233+ // The last token of the target element
234+ last : ESLintAST . Token | ESTree . Comment ;
219235} {
220236 const lastToken = getLastTokenOfNode ( sourceCode , node ) ;
221237 const afterToken = sourceCode . getTokenAfter ( lastToken ) ! ;
@@ -224,7 +240,7 @@ function getElementEndInfo(
224240 return {
225241 comma : null ,
226242 nextElement : null ,
227- end : calcEndWithTrailingComments ( ) ,
243+ last : getLastTokenWithTrailingComments ( ) ,
228244 } ;
229245 }
230246 const comma = afterToken ;
@@ -235,7 +251,7 @@ function getElementEndInfo(
235251 return {
236252 comma,
237253 nextElement : null ,
238- end : comma . range [ 1 ] ,
254+ last : comma ,
239255 } ;
240256 }
241257 if ( isClosingBrace ( nextElement ) || isClosingBracket ( nextElement ) ) {
@@ -244,7 +260,7 @@ function getElementEndInfo(
244260 return {
245261 comma,
246262 nextElement : null ,
247- end : calcEndWithTrailingComments ( ) ,
263+ last : getLastTokenWithTrailingComments ( ) ,
248264 } ;
249265 }
250266
@@ -253,7 +269,7 @@ function getElementEndInfo(
253269 return {
254270 comma,
255271 nextElement,
256- end : comma . range [ 1 ] ,
272+ last : comma ,
257273 } ;
258274 }
259275 // There are line breaks between the target element and the next element.
@@ -266,34 +282,35 @@ function getElementEndInfo(
266282 return {
267283 comma,
268284 nextElement,
269- end : comma . range [ 1 ] ,
285+ last : comma ,
270286 } ;
271287 }
272288
273289 return {
274290 comma,
275291 nextElement,
276- end : calcEndWithTrailingComments ( ) ,
292+ last : getLastTokenWithTrailingComments ( ) ,
277293 } ;
278294
279295 /**
280- * Calculate the end of the target element with trailing comments.
296+ * Get the last token of the target element with trailing comments.
281297 */
282- function calcEndWithTrailingComments ( ) {
283- let end = lastToken . range [ 1 ] ;
298+ function getLastTokenWithTrailingComments ( ) {
299+ if ( lastToken == null ) return afterToken ;
300+ let last : ESLintAST . Token | ESTree . Comment = lastToken ;
284301 let after = sourceCode . getTokenAfter ( lastToken , {
285302 includeComments : true ,
286303 } ) ! ;
287304 while (
288305 ( isCommentToken ( after ) || isComma ( after ) ) &&
289306 node . loc . end . line === after . loc ! . end . line
290307 ) {
291- end = after . range ! [ 1 ] ;
308+ last = after ;
292309 after = sourceCode . getTokenAfter ( after , {
293310 includeComments : true ,
294311 } ) ! ;
295312 }
296- return end ;
313+ return last ;
297314 }
298315}
299316
@@ -302,23 +319,24 @@ function getElementEndInfo(
302319 */
303320function getPrevElementInfo (
304321 sourceCode : SourceCode ,
305- node : AST . JSONNode ,
322+ target : Target ,
306323) : {
307324 // Leading comma
308325 comma : ESLintAST . Token | null ;
309326 // Previous element token
310327 prevElement : ESLintAST . Token | null ;
311- // The end of the range of the target element
312- end : number ;
328+ // The last token of the target element
329+ last : ESLintAST . Token | ESTree . Comment ;
313330} {
314- const firstToken = getFirstTokenOfNode ( sourceCode , node ) ;
315- const beforeToken = sourceCode . getTokenBefore ( firstToken ) ! ;
331+ const beforeToken = target . node
332+ ? sourceCode . getTokenBefore ( getFirstTokenOfNode ( sourceCode , target . node ) ) !
333+ : target . before ;
316334 if ( isNotCommaToken ( beforeToken ) ) {
317335 // If there is no comma, the element is the first element.
318336 return {
319337 comma : null ,
320338 prevElement : null ,
321- end : beforeToken . range [ 1 ] ,
339+ last : beforeToken ,
322340 } ;
323341 }
324342 const comma = beforeToken ;
@@ -330,7 +348,7 @@ function getPrevElementInfo(
330348 return {
331349 comma,
332350 prevElement : null ,
333- end : comma . range [ 1 ] ,
351+ last : comma ,
334352 } ;
335353 }
336354
@@ -339,6 +357,6 @@ function getPrevElementInfo(
339357 return {
340358 comma : endInfo . comma ,
341359 prevElement,
342- end : endInfo . end ,
360+ last : endInfo . last ,
343361 } ;
344362}
0 commit comments