@@ -106,14 +106,82 @@ function addDisableComment(filePath, api, commentText, targetLine, ruleId, path)
106106 }
107107
108108 const { children } = targetPath . parent . value ;
109- if ( tryRewriteJsxEslintDisable ( children , children . indexOf ( targetPath . value ) , ruleId ) ) {
109+
110+ // jscodeshift has some bugs around how it handles JSXText nodes that can cause
111+ // it to swallow significant whitespace. Creating whitespace only nodes appears to
112+ // solve the issue.
113+ for ( let siblingIndex = children . length - 1 ; siblingIndex >= 0 ; siblingIndex -- ) {
114+ const sibling = children [ siblingIndex ] ;
115+ if ( sibling . type !== 'JSXText' ) {
116+ continue ;
117+ }
118+
119+ if ( sibling . value [ 0 ] === '\n' && sibling . value . trim ( ) . length === 0 ) {
120+ continue ;
121+ }
122+
123+ const segments = sibling . value . split ( '\n' ) . flatMap ( ( line ) => {
124+ const trimmedLine = line . trimEnd ( ) ;
125+ if ( trimmedLine . length === 0 ) {
126+ return [ '\n' ] ;
127+ }
128+ if ( trimmedLine . length === line . length ) {
129+ return [ line , '\n' ] ;
130+ }
131+
132+ return [ trimmedLine , line . substr ( trimmedLine . length ) , '\n' ] ;
133+ } ) ;
134+
135+ segments . pop ( ) ;
136+
137+ children . splice ( siblingIndex , 1 , ...segments . map ( ( segment ) => api . j . jsxText ( segment ) ) ) ;
138+ }
139+
140+ let targetIndex = children . indexOf ( targetPath . value ) ;
141+ for ( let siblingIndex = targetIndex - 1 ; siblingIndex >= 0 ; siblingIndex -- ) {
142+ const sibling = children [ siblingIndex ] ;
143+ if ( sibling . type === 'JSXText' ) {
144+ if ( sibling . value . indexOf ( '\n' ) !== - 1 ) {
145+ break ;
146+ }
147+
148+ targetIndex = siblingIndex ;
149+ } else if ( sibling . loc ) {
150+ if ( sibling . loc . start . line !== targetLine ) {
151+ break ;
152+ }
153+
154+ targetIndex = siblingIndex ;
155+ }
156+ }
157+
158+ if ( tryRewriteJsxEslintDisable ( children , targetIndex , ruleId ) ) {
110159 return ;
111160 }
112161
113- targetPath . insertBefore ( createJsxComment ( api , commentText ) ) ;
114- targetPath . insertBefore ( api . j . jsxText ( '\n' ) ) ;
115- targetPath . insertBefore ( createJsxComment ( api , `eslint-disable-next-line ${ ruleId } ` ) ) ;
116- targetPath . insertBefore ( api . j . jsxText ( '\n' ) ) ;
162+ const previousSibling = children [ targetIndex - 1 ] ;
163+
164+ if ( previousSibling && previousSibling . type === 'JSXText' ) {
165+ const textValue = previousSibling . value ;
166+ const lastNewline = textValue . lastIndexOf ( '\n' ) ;
167+ if (
168+ lastNewline !== textValue . length - 1 &&
169+ textValue . substr ( lastNewline + 1 ) . trim ( ) . length === 0
170+ ) {
171+ previousSibling . value = textValue . substr ( 0 , lastNewline ) ;
172+ children . splice ( targetIndex , 0 , api . j . jsxText ( textValue . substr ( lastNewline ) ) ) ;
173+ targetIndex ++ ;
174+ }
175+ }
176+
177+ children . splice (
178+ targetIndex ,
179+ 0 ,
180+ createJsxComment ( api , commentText ) ,
181+ api . j . jsxText ( '\n' ) ,
182+ createJsxComment ( api , `eslint-disable-next-line ${ ruleId } ` ) ,
183+ api . j . jsxText ( '\n' )
184+ ) ;
117185
118186 return ;
119187 }
@@ -141,7 +209,7 @@ function tryRewriteJsxEslintDisable(children, targetIndex, ruleId) {
141209
142210 while ( currentIndex >= 0 ) {
143211 const sibling = children [ currentIndex ] ;
144- if ( sibling . type === 'JSXText' ) {
212+ if ( sibling . type === 'JSXText' && sibling . value . trim ( ) . length === 0 ) {
145213 currentIndex -- ;
146214 } else {
147215 if (
@@ -199,6 +267,10 @@ function tryRewriteEslintDisable(targetNode, ruleId) {
199267function createJsxComment ( api , text ) {
200268 // The <element> around the curly braces causes this to be parsed as a JSXExpressionContainer
201269 // instead of as a BlockExpression.
202- return api . j ( `<element>{/* ${ text } */}</element>` ) . paths ( ) [ 0 ] . value . program . body [ 0 ] . expression
203- . children [ 0 ] ;
270+ const expressionContainer = api . j ( `<element>{/* a comment */}</element>` ) . paths ( ) [ 0 ] . value . program
271+ . body [ 0 ] . expression . children [ 0 ] ;
272+
273+ expressionContainer . expression . innerComments [ 0 ] . value = ` ${ text } ` ;
274+
275+ return expressionContainer ;
204276}
0 commit comments