(position, sourceFile, startNode, excludeJsdoc)
| 127551 | } |
| 127552 | ts.findNextToken = findNextToken; |
| 127553 | function findPrecedingToken(position, sourceFile, startNode, excludeJsdoc) { |
| 127554 | var result = find((startNode || sourceFile)); |
| 127555 | ts.Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result))); |
| 127556 | return result; |
| 127557 | function find(n) { |
| 127558 | if (isNonWhitespaceToken(n) && n.kind !== 1 /* SyntaxKind.EndOfFileToken */) { |
| 127559 | return n; |
| 127560 | } |
| 127561 | var children = n.getChildren(sourceFile); |
| 127562 | var i = ts.binarySearchKey(children, position, function (_, i) { return i; }, function (middle, _) { |
| 127563 | // This last callback is more of a selector than a comparator - |
| 127564 | // `EqualTo` causes the `middle` result to be returned |
| 127565 | // `GreaterThan` causes recursion on the left of the middle |
| 127566 | // `LessThan` causes recursion on the right of the middle |
| 127567 | if (position < children[middle].end) { |
| 127568 | // first element whose end position is greater than the input position |
| 127569 | if (!children[middle - 1] || position >= children[middle - 1].end) { |
| 127570 | return 0 /* Comparison.EqualTo */; |
| 127571 | } |
| 127572 | return 1 /* Comparison.GreaterThan */; |
| 127573 | } |
| 127574 | return -1 /* Comparison.LessThan */; |
| 127575 | }); |
| 127576 | if (i >= 0 && children[i]) { |
| 127577 | var child = children[i]; |
| 127578 | // Note that the span of a node's tokens is [node.getStart(...), node.end). |
| 127579 | // Given that `position < child.end` and child has constituent tokens, we distinguish these cases: |
| 127580 | // 1) `position` precedes `child`'s tokens or `child` has no tokens (ie: in a comment or whitespace preceding `child`): |
| 127581 | // we need to find the last token in a previous child. |
| 127582 | // 2) `position` is within the same span: we recurse on `child`. |
| 127583 | if (position < child.end) { |
| 127584 | var start = child.getStart(sourceFile, /*includeJsDoc*/ !excludeJsdoc); |
| 127585 | var lookInPreviousChild = (start >= position) || // cursor in the leading trivia |
| 127586 | !nodeHasTokens(child, sourceFile) || |
| 127587 | isWhiteSpaceOnlyJsxText(child); |
| 127588 | if (lookInPreviousChild) { |
| 127589 | // actual start of the node is past the position - previous token should be at the end of previous child |
| 127590 | var candidate_1 = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i, sourceFile, n.kind); |
| 127591 | return candidate_1 && findRightmostToken(candidate_1, sourceFile); |
| 127592 | } |
| 127593 | else { |
| 127594 | // candidate should be in this node |
| 127595 | return find(child); |
| 127596 | } |
| 127597 | } |
| 127598 | } |
| 127599 | ts.Debug.assert(startNode !== undefined || n.kind === 305 /* SyntaxKind.SourceFile */ || n.kind === 1 /* SyntaxKind.EndOfFileToken */ || ts.isJSDocCommentContainingNode(n)); |
| 127600 | // Here we know that none of child token nodes embrace the position, |
| 127601 | // the only known case is when position is at the end of the file. |
| 127602 | // Try to find the rightmost token in the file without filtering. |
| 127603 | // Namely we are skipping the check: 'position < node.end' |
| 127604 | var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile, n.kind); |
| 127605 | return candidate && findRightmostToken(candidate, sourceFile); |
| 127606 | } |
| 127607 | } |
| 127608 | ts.findPrecedingToken = findPrecedingToken; |
| 127609 | function isNonWhitespaceToken(n) { |
| 127610 | return ts.isToken(n) && !isWhiteSpaceOnlyJsxText(n); |
no test coverage detected