55
66const variableUtil = require ( '../util/variable' ) ;
77const propsUtil = require ( '../util/props' ) ;
8+ const commentsUtil = require ( '../util/comments' ) ;
89const docsUrl = require ( '../util/docsUrl' ) ;
910
1011// ------------------------------------------------------------------------------
@@ -55,6 +56,7 @@ module.exports = {
5556 const noSortAlphabetically = configuration . noSortAlphabetically || false ;
5657 const sortShapeProp = configuration . sortShapeProp || false ;
5758 const propWrapperFunctions = new Set ( context . settings . propWrapperFunctions || [ ] ) ;
59+ const commentsAttachment = context . settings . comments || 'above' ;
5860
5961 function getKey ( node ) {
6062 if ( node . key && node . key . value ) {
@@ -120,6 +122,90 @@ module.exports = {
120122 return 0 ;
121123 }
122124
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+ }
123209
124210 /**
125211 * Checks if propTypes declarations are sorted
@@ -151,7 +237,16 @@ module.exports = {
151237 for ( let i = nodes . length - 1 ; i >= 0 ; i -- ) {
152238 const sortedAttr = sortedAttributes [ i ] ;
153239 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+
154248 let sortedAttrText = sourceCode . getText ( sortedAttr ) ;
249+
155250 if ( sortShapeProp && isShapeProp ( sortedAttr . value ) ) {
156251 const shape = getShapeProperties ( sortedAttr . value ) ;
157252 if ( shape ) {
@@ -162,16 +257,24 @@ module.exports = {
162257 sortedAttrText = attrSource . slice ( sortedAttr . range [ 0 ] , sortedAttr . range [ 1 ] ) ;
163258 }
164259 }
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 ) ;
166263 }
167264 } ) ;
168265 return source ;
169266 }
170267
171268 const source = sortInSource ( declarations , context . getSourceCode ( ) . getText ( ) ) ;
172269
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 ] ;
175278 return fixer . replaceTextRange ( [ rangeStart , rangeEnd ] , source . slice ( rangeStart , rangeEnd ) ) ;
176279 }
177280
0 commit comments