internal/ls/lsutil/utilities.go (67 lines of code) (raw):
package lsutil
import (
"strings"
"github.com/microsoft/typescript-go/internal/ast"
"github.com/microsoft/typescript-go/internal/astnav"
"github.com/microsoft/typescript-go/internal/compiler"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/scanner"
)
func ProbablyUsesSemicolons(file *ast.SourceFile) bool {
withSemicolon := 0
withoutSemicolon := 0
nStatementsToObserve := 5
var visit func(node *ast.Node) bool
visit = func(node *ast.Node) bool {
if node.Flags&ast.NodeFlagsReparsed != 0 {
return false
}
if SyntaxRequiresTrailingSemicolonOrASI(node.Kind) {
lastToken := GetLastToken(node, file)
if lastToken != nil && lastToken.Kind == ast.KindSemicolonToken {
withSemicolon++
} else {
withoutSemicolon++
}
} else if SyntaxRequiresTrailingCommaOrSemicolonOrASI(node.Kind) {
lastToken := GetLastToken(node, file)
if lastToken != nil && lastToken.Kind == ast.KindSemicolonToken {
withSemicolon++
} else if lastToken != nil && lastToken.Kind != ast.KindCommaToken {
lastTokenLine := scanner.GetECMALineOfPosition(
file,
astnav.GetStartOfNode(lastToken, file, false /*includeJSDoc*/))
nextTokenLine := scanner.GetECMALineOfPosition(
file,
scanner.SkipTrivia(file.Text(), lastToken.End()))
// Avoid counting missing semicolon in single-line objects:
// `function f(p: { x: string /*no semicolon here is insignificant*/ }) {`
if lastTokenLine != nextTokenLine {
withoutSemicolon++
}
}
}
if withSemicolon+withoutSemicolon >= nStatementsToObserve {
return true
}
return node.ForEachChild(visit)
}
file.ForEachChild(visit)
// One statement missing a semicolon isn't sufficient evidence to say the user
// doesn't want semicolons, because they may not even be done writing that statement.
if withSemicolon == 0 && withoutSemicolon <= 1 {
return true
}
// If even 2/5 places have a semicolon, the user probably wants semicolons
if withoutSemicolon == 0 {
return true
}
return withSemicolon/withoutSemicolon > 1/nStatementsToObserve
}
func ShouldUseUriStyleNodeCoreModules(file *ast.SourceFile, program *compiler.Program) bool {
for _, node := range file.Imports() {
if core.NodeCoreModules()[node.Text()] && !core.ExclusivelyPrefixedNodeCoreModules[node.Text()] {
if strings.HasPrefix(node.Text(), "node:") {
return true
} else {
return false
}
}
}
return program.UsesUriStyleNodeCoreModules()
}