findPrevious changes

This commit is contained in:
Arthur Ozga 2017-08-14 16:43:31 -07:00
parent b2188ad66c
commit 472ad9d313

View file

@ -742,18 +742,18 @@ namespace ts {
const children = n.getChildren();
for (let i = 0; i < children.length; i++) {
const child = children[i];
// condition 'position < child.end' checks if child node end after the position
// in the example below this condition will be false for 'aaaa' and 'bbbb' and true for 'ccc'
// aaaa___bbbb___$__ccc
// after we found child node with end after the position we check if start of the node is after the position.
// if yes - then position is in the trivia and we need to look into the previous child to find the token in question.
// if no - position is in the node itself so we should recurse in it.
// NOTE: JsxText is a weird kind of node that can contain only whitespaces (since they are not counted as trivia).
// if this is the case - then we should assume that token in question is located in previous child.
if (position < child.end && (nodeHasTokens(child) || child.kind === SyntaxKind.JsxText)) {
// Note that the span of a node's tokens is [node.getStart(...), node.end).
// Given that `position < child.end` and child has constiutent tokens*, we distinguish these cases:
// 1) `position` precedes `child`'s tokens or `child` has no tokens (ie: in a comment or whitespace preceding `child`):
// we need to find the last token in a previous child.
// 2) `position` is within the same span: we recurse on `child`.
// * JsxText is exceptional in that its tokens are (non-trivia) whitespace, which we do not want to return.
// TODO(arozga): shouldn't `findRightmost...` need to handle JsxText?
if (position < child.end) {
const start = child.getStart(sourceFile, includeJsDoc);
const lookInPreviousChild =
(start >= position) || // cursor in the leading trivia
nodeHasTokens(child) ||
(child.kind === SyntaxKind.JsxText && start === child.end); // whitespace only JsxText
if (lookInPreviousChild) {
@ -768,7 +768,7 @@ namespace ts {
}
}
Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || isJSDocCommentContainingNode(n));
Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || isJSDocCommentContainingNode(n) || n.kind === SyntaxKind.JsxSelfClosingElement);
// Here we know that none of child token nodes embrace the position,
// the only known case is when position is at the end of the file.
@ -780,7 +780,9 @@ namespace ts {
}
}
/// finds last node that is considered as candidate for search (isCandidate(node) === true) starting from 'exclusiveStartPosition'
/**
* Finds the rightmost child to the left of `children[exclusiveStartPosition]` which has constituent tokens.
*/
function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number): Node {
for (let i = exclusiveStartPosition - 1; i >= 0; i--) {
if (nodeHasTokens(children[i])) {
@ -863,41 +865,11 @@ namespace ts {
* @param predicate Additional predicate to test on the comment range.
*/
export function isInComment(
sourceFile: SourceFile,
position: number,
tokenAtPosition = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false),
predicate?: (c: CommentRange) => boolean): boolean {
return position <= tokenAtPosition.getStart(sourceFile) &&
(isInCommentRange(getLeadingCommentRanges(sourceFile.text, tokenAtPosition.pos)) ||
isInCommentRange(getTrailingCommentRanges(sourceFile.text, tokenAtPosition.pos)));
function isInCommentRange(commentRanges: CommentRange[]): boolean {
return forEach(commentRanges, c => isPositionInCommentRange(c, position, sourceFile.text) && (!predicate || predicate(c)));
}
}
function isPositionInCommentRange({ pos, end, kind }: ts.CommentRange, position: number, text: string): boolean {
if (pos < position && position < end) {
return true;
}
else if (position === end) {
// The end marker of a single-line comment does not include the newline character.
// In the following case, we are inside a comment (^ denotes the cursor position):
//
// // asdf ^\n
//
// But for multi-line comments, we don't want to be inside the comment in the following case:
//
// /* asdf */^
//
// Internally, we represent the end of the comment at the newline and closing '/', respectively.
return kind === SyntaxKind.SingleLineCommentTrivia ||
// true for unterminated multi-line comment
!(text.charCodeAt(end - 1) === CharacterCodes.slash && text.charCodeAt(end - 2) === CharacterCodes.asterisk);
}
else {
return false;
}
sourceFile: SourceFile,
position: number,
tokenAtPosition = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false),
predicate?: (c: CommentRange) => boolean): boolean {
return !!formatting.getRangeOfEnclosingComment(sourceFile, position, /*onlyMultiLine*/ false, tokenAtPosition, predicate);
}
export function hasDocComment(sourceFile: SourceFile, position: number) {