@@ -65,6 +65,10 @@ func getTokenAtPosition(
6565 // `left` tracks the lower boundary of the node/token that could be returned,
6666 // and is eventually the scanner's start position, if the scanner is used.
6767 left := 0
68+ // `allowReparsed` is set when we're navigating inside an AsExpression or
69+ // SatisfiesExpression, which allows visiting their reparsed children to reach
70+ // the actual identifier from JSDoc type assertions.
71+ allowReparsed := false
6872
6973 testNode := func (node * ast.Node ) int {
7074 if node .Kind != ast .KindEndOfFile && node .End () == position && includePrecedingTokenAtEndPosition != nil {
@@ -74,7 +78,8 @@ func getTokenAtPosition(
7478 if node .End () < position || node .Kind != ast .KindEndOfFile && node .End () == position {
7579 return - 1
7680 }
77- if getPosition (node , sourceFile , allowPositionInLeadingTrivia ) > position {
81+ nodePos := getPosition (node , sourceFile , allowPositionInLeadingTrivia )
82+ if nodePos > position {
7883 return 1
7984 }
8085 return 0
@@ -86,18 +91,29 @@ func getTokenAtPosition(
8691 visitNode := func (node * ast.Node , _ * ast.NodeVisitor ) * ast.Node {
8792 // We can't abort visiting children, so once a match is found, we set `next`
8893 // and do nothing on subsequent visits.
89- if node != nil && node .Flags & ast .NodeFlagsReparsed == 0 && next == nil {
90- switch testNode (node ) {
91- case - 1 :
92- if ! ast .IsJSDocKind (node .Kind ) {
93- // We can't move the left boundary into or beyond JSDoc,
94- // because we may end up returning the token after this JSDoc,
95- // constructing it with the scanner, and we need to include
96- // all its leading trivia in its position.
97- left = node .End ()
94+ if node != nil && next == nil {
95+ // Skip reparsed nodes unless:
96+ // 1. The node itself is AsExpression or SatisfiesExpression, OR
97+ // 2. We're already inside an AsExpression or SatisfiesExpression (allowReparsed=true)
98+ // These are special cases where reparsed nodes from JSDoc type assertions
99+ // should still be navigable to reach identifiers.
100+ isSpecialReparsed := node .Flags & ast .NodeFlagsReparsed != 0 &&
101+ (node .Kind == ast .KindAsExpression || node .Kind == ast .KindSatisfiesExpression )
102+
103+ if node .Flags & ast .NodeFlagsReparsed == 0 || isSpecialReparsed || allowReparsed {
104+ result := testNode (node )
105+ switch result {
106+ case - 1 :
107+ if ! ast .IsJSDocKind (node .Kind ) {
108+ // We can't move the left boundary into or beyond JSDoc,
109+ // because we may end up returning the token after this JSDoc,
110+ // constructing it with the scanner, and we need to include
111+ // all its leading trivia in its position.
112+ left = node .End ()
113+ }
114+ case 0 :
115+ next = node
98116 }
99- case 0 :
100- next = node
101117 }
102118 }
103119 return node
@@ -194,6 +210,11 @@ func getTokenAtPosition(
194210 current = next
195211 left = current .Pos ()
196212 next = nil
213+ // When navigating into AsExpression or SatisfiesExpression, allow visiting
214+ // their reparsed children to reach identifiers from JSDoc type assertions.
215+ if current .Kind == ast .KindAsExpression || current .Kind == ast .KindSatisfiesExpression {
216+ allowReparsed = true
217+ }
197218 }
198219}
199220
0 commit comments