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