@@ -345,82 +345,70 @@ module ts {
345
345
// return null;
346
346
//}
347
347
348
- export function findClosestRightmostSiblingFromLeft ( position : number , sourceFile : SourceFile ) : Node {
349
- return search ( sourceFile ) ;
350
-
351
- function search ( n : Node ) : Node {
352
-
353
- var childCandidate : Node ;
354
- forEachChild ( n , c => {
355
- if ( c . kind === SyntaxKind . OmittedExpression || c . kind === SyntaxKind . Missing ) {
356
- return ;
357
- }
358
- if ( c . end <= position || c . getStart ( ) < position ) {
359
- childCandidate = c ;
360
- }
361
- return c . end > position ;
362
- } ) ;
363
-
364
- if ( childCandidate ) {
365
- if ( childCandidate . end > position || ! isCompletedNode ( childCandidate , position , sourceFile ) ) {
366
- return search ( childCandidate ) || childCandidate ;
367
- }
368
- else {
369
- return childCandidate ;
370
- }
371
- }
372
- }
348
+ export function findPrecedingToken ( position : number , sourceFile : SourceFile ) : Node {
349
+ return find ( sourceFile , /*diveIntoLastChild*/ false ) ;
350
+
351
+ function find ( n : Node , diveIntoLastChild : boolean ) : Node {
352
+ if ( isToken ( n ) ) {
353
+ return n ;
354
+ }
355
+
356
+ var children = n . getChildren ( ) ;
357
+ if ( diveIntoLastChild ) {
358
+ var candidate = findLastChildNodeCandidate ( children , /*exclusiveStartPosition*/ children . length ) ;
359
+ return candidate && find ( candidate , /*diveIntoLastChild*/ true ) ;
360
+ }
361
+
362
+ for ( var i = 0 , len = children . length ; i < len ; ++ i ) {
363
+ var child = children [ i ] ;
364
+ if ( nodeHasTokens ( child ) ) {
365
+ if ( position < child . end ) {
366
+ if ( child . getStart ( ) >= position ) {
367
+ // actual start of the node is past the position - previous token should be at the end of previous child
368
+ var candidate = findLastChildNodeCandidate ( children , /*exclusiveStartPosition*/ i ) ;
369
+ return candidate && find ( candidate , /*diveIntoLastChild*/ true )
370
+ }
371
+ else {
372
+ // candidate should be in this node
373
+ return find ( child , diveIntoLastChild ) ;
374
+ }
375
+ }
376
+ }
377
+ }
378
+
379
+ // here we know that none of child token nodes embrace the position
380
+ // try to find the closest token on the left
381
+ if ( children . length ) {
382
+ var candidate = findLastChildNodeCandidate ( children , /*exclusiveStartPosition*/ children . length ) ;
383
+ return candidate && find ( candidate , /*diveIntoLastChild*/ true ) ;
384
+ }
385
+ }
386
+
387
+ /// finds last node that is considered as candidate for search (isCandidate(node) === true) starting from 'exclusiveStartPosition'
388
+ function findLastChildNodeCandidate ( children : Node [ ] , exclusiveStartPosition : number ) : Node {
389
+ for ( var i = exclusiveStartPosition - 1 ; i >= 0 ; -- i ) {
390
+ if ( nodeHasTokens ( children [ i ] ) ) {
391
+ return children [ i ] ;
392
+ }
393
+ }
394
+ }
395
+
396
+ function isToken ( n : Node ) : boolean {
397
+ return n . kind < SyntaxKind . Missing ;
398
+ }
399
+
400
+ function nodeHasTokens ( n : Node ) : boolean {
401
+ if ( n . kind === SyntaxKind . ExpressionStatement ) {
402
+ return nodeHasTokens ( ( < ExpressionStatement > n ) . expression ) ;
403
+ }
404
+
405
+ if ( n . kind === SyntaxKind . EndOfFileToken || n . kind === SyntaxKind . OmittedExpression || n . kind === SyntaxKind . Missing ) {
406
+ return false ;
407
+ }
408
+
409
+ // SyntaxList is already realized so getChildCount should be fast and non-expensive
410
+ return n . kind !== SyntaxKind . SyntaxList || n . getChildCount ( ) !== 0 ;
411
+ }
373
412
}
374
-
375
- function isCompletedNode ( n : Node , position : number , sourceFile : SourceFile ) : boolean {
376
- switch ( n . kind ) {
377
- case SyntaxKind . ClassDeclaration :
378
- case SyntaxKind . InterfaceDeclaration :
379
- case SyntaxKind . EnumDeclaration :
380
- case SyntaxKind . ObjectLiteral :
381
- case SyntaxKind . Block :
382
- case SyntaxKind . CatchBlock :
383
- case SyntaxKind . FinallyBlock :
384
- case SyntaxKind . FunctionBlock :
385
- case SyntaxKind . ModuleBlock :
386
- return isNodeEndWith ( n , sourceFile , CharacterCodes . closeBrace ) ;
387
- case SyntaxKind . ParenExpression :
388
- case SyntaxKind . CallSignature :
389
- case SyntaxKind . CallExpression :
390
- return isNodeEndWith ( n , sourceFile , CharacterCodes . closeParen ) ;
391
- case SyntaxKind . FunctionDeclaration :
392
- case SyntaxKind . FunctionExpression :
393
- case SyntaxKind . Method :
394
- case SyntaxKind . ArrowFunction :
395
- return ! ( < FunctionDeclaration > n ) . body || isCompletedNode ( ( < FunctionDeclaration > n ) . body , position , sourceFile ) ;
396
- case SyntaxKind . ModuleDeclaration :
397
- return ( < ModuleDeclaration > n ) . body && isCompletedNode ( ( < ModuleDeclaration > n ) . body , position , sourceFile ) ;
398
- case SyntaxKind . IfStatement :
399
- if ( ( < IfStatement > n ) . thenStatement && ( < IfStatement > n ) . thenStatement . end > position ) {
400
- return isCompletedNode ( ( < IfStatement > n ) . thenStatement , position , sourceFile ) ;
401
- }
402
- else if ( ( < IfStatement > n ) . elseStatement ) {
403
- return isCompletedNode ( ( < IfStatement > n ) . elseStatement , position , sourceFile ) ;
404
- }
405
- else {
406
- return true ;
407
- }
408
- break ;
409
- case SyntaxKind . ExpressionStatement :
410
- return isCompletedNode ( ( < ExpressionStatement > n ) . expression , position , sourceFile ) ;
411
- case SyntaxKind . ArrayLiteral :
412
- return isNodeEndWith ( n , sourceFile , CharacterCodes . closeBracket ) ;
413
- case SyntaxKind . Missing :
414
- return false ;
415
- default :
416
- return true ;
417
- }
418
- }
419
-
420
- function isNodeEndWith ( n : Node , sourceFile : SourceFile , charCode : CharacterCodes ) : boolean {
421
- var pos = n . end - 1 ; // Node.end is exclusive
422
- return pos < sourceFile . text . length && sourceFile . text . charCodeAt ( pos ) === charCode ;
423
- }
424
-
425
413
}
426
414
}
0 commit comments