@@ -47,28 +47,22 @@ export function getCommentsBefore(nodeOrToken: NodeOrToken): Comment[] {
4747 let sliceStart = commentsLength ;
4848 let sliceEnd = 0 ;
4949
50- // Reverse iteration isn't ideal, but this entire implementation may need to be rewritten
51- // with token-based APIs to match eslint.
52- for ( let i = commentsLength - 1 ; i >= 0 ; i -- ) {
53- const comment = comments [ i ] ;
54- const commentEnd = comment . end ;
55-
56- if ( commentEnd < targetStart ) {
57- const gap = sourceText . slice ( commentEnd , targetStart ) ;
58- if ( WHITESPACE_ONLY_REGEXP . test ( gap ) ) {
59- // Nothing except whitespace between end of comment and start of `nodeOrToken`
60- sliceStart = sliceEnd = i + 1 ;
61- targetStart = comment . start ;
62- }
63- break ;
50+ // Binary search for the comment immediately before `nodeOrToken`.
51+ for ( let lo = 0 , hi = commentsLength ; lo < hi ; ) {
52+ const mid = ( lo + hi ) >> 1 ;
53+ if ( comments [ mid ] . end <= targetStart ) {
54+ sliceEnd = lo = mid + 1 ;
55+ } else {
56+ hi = mid ;
6457 }
6558 }
6659
6760 for ( let i = sliceEnd - 1 ; i >= 0 ; i -- ) {
6861 const comment = comments [ i ] ;
6962 const gap = sourceText . slice ( comment . end , targetStart ) ;
63+ // Ensure that there is nothing except whitespace between the end of the
64+ // current comment and the start of the next as we iterate backwards.
7065 if ( WHITESPACE_ONLY_REGEXP . test ( gap ) ) {
71- // Nothing except whitespace between end of comment and start of `nodeOrToken`
7266 sliceStart = i ;
7367 targetStart = comment . start ;
7468 } else {
@@ -105,25 +99,33 @@ export function getCommentsAfter(nodeOrToken: NodeOrToken): Comment[] {
10599
106100 let targetEnd = nodeOrToken . range [ 1 ] ; // end
107101
108- const commentsAfter : Comment [ ] = [ ] ;
109- for ( let i = 0 ; i < commentsLength ; i ++ ) {
110- const comment = comments [ i ] ,
111- commentStart = comment . start ;
102+ let sliceStart = commentsLength ;
103+ let sliceEnd = 0 ;
112104
113- if ( commentStart < targetEnd ) {
114- continue ;
105+ // Binary search for the comment immediately after `nodeOrToken`.
106+ for ( let lo = 0 , hi = commentsLength ; lo < hi ; ) {
107+ const mid = ( lo + hi ) >> 1 ;
108+ if ( comments [ mid ] . start < targetEnd ) {
109+ lo = mid + 1 ;
110+ } else {
111+ sliceStart = hi = mid ;
115112 }
116- const gap = sourceText . slice ( targetEnd , commentStart ) ;
113+ }
114+
115+ for ( let i = sliceStart ; i < commentsLength ; i ++ ) {
116+ // Ensure that there is nothing except whitespace between the
117+ // end of the previous comment and the start of the current.
118+ const comment = comments [ i ] ;
119+ const gap = sourceText . slice ( targetEnd , comment . start ) ;
117120 if ( WHITESPACE_ONLY_REGEXP . test ( gap ) ) {
118- // Nothing except whitespace between end of `nodeOrToken` and start of comment
119- commentsAfter . push ( comment ) ;
121+ sliceEnd = i + 1 ;
120122 targetEnd = comment . end ;
121123 } else {
122124 break ;
123125 }
124126 }
125127
126- return commentsAfter ;
128+ return comments . slice ( sliceStart , sliceEnd ) ;
127129}
128130
129131/**
@@ -144,23 +146,24 @@ export function getCommentsInside(node: Node): Comment[] {
144146 rangeStart = range [ 0 ] ,
145147 rangeEnd = range [ 1 ] ;
146148
147- // Linear search for first comment within `node`'s range.
148- // TODO: Use binary search.
149- for ( let i = 0 ; i < commentsLength ; i ++ ) {
150- const comment = comments [ i ] ;
151- if ( comment . start >= rangeStart ) {
152- sliceStart = i ;
153- break ;
149+ // Binary search for first comment within `node`'s range.
150+ for ( let lo = 0 , hi = commentsLength ; lo < hi ; ) {
151+ const mid = ( lo + hi ) >> 1 ;
152+ if ( comments [ mid ] . start < rangeStart ) {
153+ lo = mid + 1 ;
154+ } else {
155+ sliceStart = hi = mid ;
154156 }
155157 }
156158
157- // Continued linear search for first comment outside `node`'s range.
159+ // Binary search for first comment outside `node`'s range.
158160 // Its index is used as `sliceEnd`, which is exclusive of the slice.
159- for ( let i = sliceStart ; i < commentsLength ; i ++ ) {
160- const comment = comments [ i ] ;
161- if ( comment . start > rangeEnd ) {
162- sliceEnd = i ;
163- break ;
161+ for ( let lo = sliceStart , hi = commentsLength ; lo < hi ; ) {
162+ const mid = ( lo + hi ) >> 1 ;
163+ if ( comments [ mid ] . start < rangeEnd ) {
164+ lo = mid + 1 ;
165+ } else {
166+ sliceEnd = hi = mid ;
164167 }
165168 }
166169
@@ -177,15 +180,20 @@ export function commentsExistBetween(nodeOrToken1: NodeOrToken, nodeOrToken2: No
177180 if ( ast === null ) initAst ( ) ;
178181
179182 // Find the first comment after `nodeOrToken1` ends.
180- // Check if it ends before `nodeOrToken2` starts.
181183 const { comments } = ast ,
182- commentsLength = comments . length ;
183- const betweenRangeStart = nodeOrToken1 . range [ 1 ] ; // end
184- for ( let i = 0 ; i < commentsLength ; i ++ ) {
185- const comment = comments [ i ] ;
186- if ( comment . start >= betweenRangeStart ) {
187- return comment . end <= nodeOrToken2 . range [ 0 ] ; // start
184+ commentsLength = comments . length ,
185+ betweenRangeStart = nodeOrToken1 . range [ 1 ] ;
186+ let firstCommentBetween = - 1 ;
187+
188+ for ( let lo = 0 , hi = commentsLength ; lo < hi ; ) {
189+ const mid = ( lo + hi ) >> 1 ;
190+ if ( comments [ mid ] . start < betweenRangeStart ) {
191+ lo = mid + 1 ;
192+ } else {
193+ firstCommentBetween = hi = mid ;
188194 }
189195 }
190- return false ;
196+ // Check if it ends before `nodeOrToken2` starts.
197+ return 0 <= firstCommentBetween && firstCommentBetween < commentsLength &&
198+ comments [ firstCommentBetween ] . end <= nodeOrToken2 . range [ 0 ] ;
191199}
0 commit comments