5
5
6
6
const variableUtil = require ( '../util/variable' ) ;
7
7
const propsUtil = require ( '../util/props' ) ;
8
+ const commentsUtil = require ( '../util/comments' ) ;
8
9
const docsUrl = require ( '../util/docsUrl' ) ;
9
10
10
11
// ------------------------------------------------------------------------------
@@ -55,6 +56,7 @@ module.exports = {
55
56
const noSortAlphabetically = configuration . noSortAlphabetically || false ;
56
57
const sortShapeProp = configuration . sortShapeProp || false ;
57
58
const propWrapperFunctions = new Set ( context . settings . propWrapperFunctions || [ ] ) ;
59
+ const commentsAttachment = context . settings . comments || 'above' ;
58
60
59
61
function getKey ( node ) {
60
62
return sourceCode . getText ( node . key || node . argument ) ;
@@ -117,6 +119,90 @@ module.exports = {
117
119
return 0 ;
118
120
}
119
121
122
+ function getRelatedComments ( node , nextNode ) {
123
+ // check for an end of line comment
124
+ const nextNodeComments = nextNode
125
+ ? commentsUtil . getCommentsBefore ( nextNode , sourceCode )
126
+ : commentsUtil . getCommentsAfter ( node , sourceCode ) ;
127
+ if ( nextNodeComments . length === 1 ) {
128
+ const comment = nextNodeComments [ 0 ] ;
129
+ if ( comment . loc . start . line === comment . loc . end . line && comment . loc . end . line === node . loc . end . line ) {
130
+ return { comments : nextNodeComments , isSameLine : true } ;
131
+ }
132
+ }
133
+
134
+ if ( commentsAttachment === 'above' ) {
135
+ return { comments : commentsUtil . getCommentsBefore ( node , sourceCode ) , isSameLine : false } ;
136
+ }
137
+
138
+ return { comments : nextNodeComments , isSameLine : false } ;
139
+ }
140
+
141
+ function replaceNodeWithText ( source , originalNode , sortedNodeText ) {
142
+ return `${ source . slice ( 0 , originalNode . range [ 0 ] ) } ${ sortedNodeText } ${ source . slice ( originalNode . range [ 1 ] ) } ` ;
143
+ }
144
+
145
+ function sortNodeWithComments ( source , originalAttr , originalComments , sortedAttrText , sortedComments ) {
146
+ if ( sortedComments . length && originalComments . length ) {
147
+ const swapComments = ( ) => {
148
+ const sortedCommentsText = sourceCode . getText ( ) . slice (
149
+ sortedComments [ 0 ] . range [ 0 ] ,
150
+ sortedComments [ sortedComments . length - 1 ] . range [ 1 ]
151
+ ) ;
152
+ return `${ source . slice ( 0 , originalComments [ 0 ] . range [ 0 ] ) } ${ sortedCommentsText } ${ source . slice ( originalComments [ originalComments . length - 1 ] . range [ 1 ] ) } ` ;
153
+ } ;
154
+ if ( originalAttr . range [ 1 ] < originalComments [ 0 ] . range [ 0 ] ) {
155
+ source = swapComments ( ) ;
156
+ source = replaceNodeWithText ( source , originalAttr , sortedAttrText ) ;
157
+ } else {
158
+ source = replaceNodeWithText ( source , originalAttr , sortedAttrText ) ;
159
+ source = swapComments ( ) ;
160
+ }
161
+ return source ;
162
+ }
163
+
164
+ if ( sortedComments . length ) {
165
+ const sortedCommentsText = sourceCode . getText ( ) . slice (
166
+ sortedComments [ 0 ] . range [ 0 ] ,
167
+ sortedComments [ sortedComments . length - 1 ] . range [ 1 ]
168
+ ) ;
169
+
170
+ const indent = Array ( sortedComments [ 0 ] . loc . start . column + 1 ) . join ( ' ' ) ;
171
+ if ( commentsAttachment === 'above' ) {
172
+ source = replaceNodeWithText ( source , originalAttr , sortedAttrText ) ;
173
+ source = `${ source . slice ( 0 , originalAttr . range [ 0 ] ) } ${ sortedCommentsText } \n${ indent } ${ source . slice ( originalAttr . range [ 0 ] ) } ` ;
174
+ } else {
175
+ const nextToken = sourceCode . getTokenAfter ( originalAttr ) ;
176
+ const targetIndex = nextToken . value === ',' ? nextToken . range [ 1 ] : originalAttr . range [ 1 ] ;
177
+ source = `${ source . slice ( 0 , targetIndex ) } \n${ indent } ${ sortedCommentsText } ${ source . slice ( targetIndex ) } ` ;
178
+ source = replaceNodeWithText ( source , originalAttr , sortedAttrText ) ;
179
+ }
180
+ return source ;
181
+ }
182
+
183
+ if ( originalComments . length ) {
184
+ const removeComments = ( ) => {
185
+ const startLoc = sourceCode . getLocFromIndex ( originalComments [ 0 ] . range [ 0 ] ) ;
186
+ const lineStart = sourceCode . getIndexFromLoc ( { line : startLoc . line , column : 0 } ) ;
187
+ const endLoc = sourceCode . getLocFromIndex ( originalComments [ originalComments . length - 1 ] . range [ 1 ] ) ;
188
+ const lineEnd = sourceCode . getIndexFromLoc ( {
189
+ line : endLoc . line ,
190
+ column : sourceCode . lines [ endLoc . line - 1 ] . length - 1
191
+ } ) ;
192
+ return `${ source . slice ( 0 , lineStart ) } ${ source . slice ( lineEnd + 2 ) } ` ;
193
+ } ;
194
+ if ( originalAttr . range [ 1 ] < originalComments [ 0 ] . range [ 0 ] ) {
195
+ source = removeComments ( ) ;
196
+ source = replaceNodeWithText ( source , originalAttr , sortedAttrText ) ;
197
+ } else {
198
+ source = replaceNodeWithText ( source , originalAttr , sortedAttrText ) ;
199
+ source = removeComments ( ) ;
200
+ }
201
+ return source ;
202
+ }
203
+
204
+ return null ;
205
+ }
120
206
121
207
/**
122
208
* Checks if propTypes declarations are sorted
@@ -148,7 +234,16 @@ module.exports = {
148
234
for ( let i = nodes . length - 1 ; i >= 0 ; i -- ) {
149
235
const sortedAttr = sortedAttributes [ i ] ;
150
236
const attr = nodes [ i ] ;
237
+ if ( sortedAttr === attr ) {
238
+ continue ;
239
+ }
240
+
241
+ const sortedComments = getRelatedComments ( sortedAttr ,
242
+ allNodes [ allNodes . indexOf ( sortedAttr ) + 1 ] ) . comments ;
243
+ const attrComments = getRelatedComments ( attr , nodes [ i + 1 ] ) . comments ;
244
+
151
245
let sortedAttrText = sourceCode . getText ( sortedAttr ) ;
246
+
152
247
if ( sortShapeProp && isShapeProp ( sortedAttr . value ) ) {
153
248
const shape = getShapeProperties ( sortedAttr . value ) ;
154
249
if ( shape ) {
@@ -159,16 +254,24 @@ module.exports = {
159
254
sortedAttrText = attrSource . slice ( sortedAttr . range [ 0 ] , sortedAttr . range [ 1 ] ) ;
160
255
}
161
256
}
162
- source = `${ source . slice ( 0 , attr . range [ 0 ] ) } ${ sortedAttrText } ${ source . slice ( attr . range [ 1 ] ) } ` ;
257
+
258
+ const newSource = sortNodeWithComments ( source , attr , attrComments , sortedAttrText , sortedComments ) ;
259
+ source = newSource || replaceNodeWithText ( source , attr , sortedAttrText ) ;
163
260
}
164
261
} ) ;
165
262
return source ;
166
263
}
167
264
168
265
const source = sortInSource ( declarations , context . getSourceCode ( ) . getText ( ) ) ;
169
266
170
- const rangeStart = declarations [ 0 ] . range [ 0 ] ;
171
- const rangeEnd = declarations [ declarations . length - 1 ] . range [ 1 ] ;
267
+ const startComments = getRelatedComments ( declarations [ 0 ] , declarations [ 1 ] ) ;
268
+ const endComments = getRelatedComments ( declarations [ declarations . length - 1 ] , null ) ;
269
+ const rangeStart = ( commentsAttachment === 'above' && startComments . comments . length && ! startComments . isSameLine )
270
+ ? startComments . comments [ 0 ] . range [ 0 ]
271
+ : declarations [ 0 ] . range [ 0 ] ;
272
+ const rangeEnd = ( commentsAttachment === 'below' && endComments . comments . length || endComments . isSameLine )
273
+ ? endComments . comments [ endComments . comments . length - 1 ] . range [ 1 ]
274
+ : declarations [ declarations . length - 1 ] . range [ 1 ] ;
172
275
return fixer . replaceTextRange ( [ rangeStart , rangeEnd ] , source . slice ( rangeStart , rangeEnd ) ) ;
173
276
}
174
277
0 commit comments