2025-10-15 10:12:44 +03:00

105 lines
3.5 KiB
Go

package lsutil
import (
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/astnav"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/scanner"
)
func PositionIsASICandidate(pos int, context *ast.Node, file *ast.SourceFile) bool {
contextAncestor := ast.FindAncestorOrQuit(context, func(ancestor *ast.Node) ast.FindAncestorResult {
if ancestor.End() != pos {
return ast.FindAncestorQuit
}
return ast.ToFindAncestorResult(SyntaxMayBeASICandidate(ancestor.Kind))
})
return contextAncestor != nil && NodeIsASICandidate(contextAncestor, file)
}
func SyntaxMayBeASICandidate(kind ast.Kind) bool {
return SyntaxRequiresTrailingCommaOrSemicolonOrASI(kind) ||
SyntaxRequiresTrailingFunctionBlockOrSemicolonOrASI(kind) ||
SyntaxRequiresTrailingModuleBlockOrSemicolonOrASI(kind) ||
SyntaxRequiresTrailingSemicolonOrASI(kind)
}
func SyntaxRequiresTrailingCommaOrSemicolonOrASI(kind ast.Kind) bool {
return kind == ast.KindCallSignature ||
kind == ast.KindConstructSignature ||
kind == ast.KindIndexSignature ||
kind == ast.KindPropertySignature ||
kind == ast.KindMethodSignature
}
func SyntaxRequiresTrailingFunctionBlockOrSemicolonOrASI(kind ast.Kind) bool {
return kind == ast.KindFunctionDeclaration ||
kind == ast.KindConstructor ||
kind == ast.KindMethodDeclaration ||
kind == ast.KindGetAccessor ||
kind == ast.KindSetAccessor
}
func SyntaxRequiresTrailingModuleBlockOrSemicolonOrASI(kind ast.Kind) bool {
return kind == ast.KindModuleDeclaration
}
func SyntaxRequiresTrailingSemicolonOrASI(kind ast.Kind) bool {
return kind == ast.KindVariableStatement ||
kind == ast.KindExpressionStatement ||
kind == ast.KindDoStatement ||
kind == ast.KindContinueStatement ||
kind == ast.KindBreakStatement ||
kind == ast.KindReturnStatement ||
kind == ast.KindThrowStatement ||
kind == ast.KindDebuggerStatement ||
kind == ast.KindPropertyDeclaration ||
kind == ast.KindTypeAliasDeclaration ||
kind == ast.KindImportDeclaration ||
kind == ast.KindImportEqualsDeclaration ||
kind == ast.KindExportDeclaration ||
kind == ast.KindNamespaceExportDeclaration ||
kind == ast.KindExportAssignment
}
func NodeIsASICandidate(node *ast.Node, file *ast.SourceFile) bool {
lastToken := GetLastToken(node, file)
if lastToken != nil && lastToken.Kind == ast.KindSemicolonToken {
return false
}
if SyntaxRequiresTrailingCommaOrSemicolonOrASI(node.Kind) {
if lastToken != nil && lastToken.Kind == ast.KindCommaToken {
return false
}
} else if SyntaxRequiresTrailingModuleBlockOrSemicolonOrASI(node.Kind) {
lastChild := GetLastChild(node, file)
if lastChild != nil && ast.IsModuleBlock(lastChild) {
return false
}
} else if SyntaxRequiresTrailingFunctionBlockOrSemicolonOrASI(node.Kind) {
lastChild := GetLastChild(node, file)
if lastChild != nil && ast.IsFunctionBlock(lastChild) {
return false
}
} else if !SyntaxRequiresTrailingSemicolonOrASI(node.Kind) {
return false
}
// See comment in parser's `parseDoStatement`
if node.Kind == ast.KindDoStatement {
return true
}
topNode := ast.FindAncestor(node, func(ancestor *ast.Node) bool { return ancestor.Parent == nil })
nextToken := astnav.FindNextToken(node, topNode, file)
if nextToken == nil || nextToken.Kind == ast.KindCloseBraceToken {
return true
}
startLine, _ := scanner.GetECMALineAndCharacterOfPosition(file, node.End())
endLine, _ := scanner.GetECMALineAndCharacterOfPosition(file, astnav.GetStartOfNode(nextToken, file, false /*includeJSDoc*/))
return startLine != endLine
}