Skip to content

Commit a26175b

Browse files
authored
Ensure findPrecedingToken recurses into JSDoc children when needed (#53487)
1 parent bec204c commit a26175b

File tree

3 files changed

+29
-1
lines changed

3 files changed

+29
-1
lines changed

src/services/utilities.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1739,7 +1739,14 @@ export function findPrecedingToken(position: number, sourceFile: SourceFileLike,
17391739
if (lookInPreviousChild) {
17401740
// actual start of the node is past the position - previous token should be at the end of previous child
17411741
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i, sourceFile, n.kind);
1742-
return candidate && findRightmostToken(candidate, sourceFile);
1742+
if (candidate) {
1743+
// Ensure we recurse into JSDoc nodes with children.
1744+
if (!excludeJsdoc && isJSDocCommentContainingNode(candidate) && candidate.getChildren(sourceFile).length) {
1745+
return find(candidate);
1746+
}
1747+
return findRightmostToken(candidate, sourceFile);
1748+
}
1749+
return undefined;
17431750
}
17441751
else {
17451752
// candidate should be in this node

src/testRunner/tests.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import "./unittests/services/patternMatcher";
6161
import "./unittests/services/preProcessFile";
6262
import "./unittests/services/textChanges";
6363
import "./unittests/services/transpile";
64+
import "./unittests/services/utilities";
6465
import "./unittests/tsbuild/amdModulesWithOut";
6566
import "./unittests/tsbuild/clean";
6667
import "./unittests/tsbuild/commandLine";
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as ts from "../../_namespaces/ts";
2+
3+
describe("unittests:: services:: utilities", () => {
4+
describe("Test findPrecedingMatchingToken,", () => {
5+
it("should not infinite loop finding opening brace", () => {
6+
const sourceFile = ts.createSourceFile("file.ts", `/// <reference path="./compiler.d.ts" />
7+
8+
(/** @window => {
9+
/** @type {Abcd123} */
10+
const core = window.Abcd.core;
11+
})();`, ts.ScriptTarget.ESNext, /*setParentNodes*/ true);
12+
// can't use ts.getTokenAtPosition because it returns back the wrong token
13+
const param = ts.forEachChildRecursively(sourceFile, node => node.kind === ts.SyntaxKind.Parameter ? node : undefined)!;
14+
const jsDoc = param.getChildren()[0];
15+
const token = jsDoc.getLastToken()!;
16+
const result = ts.findPrecedingMatchingToken(token, ts.SyntaxKind.OpenBraceToken, sourceFile);
17+
assert.isDefined(result);
18+
});
19+
});
20+
});

0 commit comments

Comments
 (0)