vendor tsgo
This commit is contained in:
161
tools/tsgo/internal/ls/jsdoc.go
Normal file
161
tools/tsgo/internal/ls/jsdoc.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package ls
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/microsoft/typescript-go/internal/ast"
|
||||
"github.com/microsoft/typescript-go/internal/checker"
|
||||
"github.com/microsoft/typescript-go/internal/collections"
|
||||
"github.com/microsoft/typescript-go/internal/core"
|
||||
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
|
||||
"github.com/microsoft/typescript-go/internal/scanner"
|
||||
)
|
||||
|
||||
// JSDocTagInfo mirrors Strada's `JSDocTagInfo`, but renders the tag's text as a
|
||||
// plain string instead of `SymbolDisplayPart[]`.
|
||||
type JSDocTagInfo struct {
|
||||
Name string
|
||||
Text string
|
||||
}
|
||||
|
||||
// GetSymbolDocumentationComment renders a symbol's documentation comment as plain text.
|
||||
// It backs the API's Symbol.getDocumentationComment and mirrors Strada's
|
||||
// getJsDocCommentsFromDeclarations: comments are gathered from each unique declaration,
|
||||
// deduplicated, and joined with line breaks. Like Strada, it does not resolve aliases —
|
||||
// consumers resolve aliases themselves (via getAliasedSymbol) and re-query if desired.
|
||||
func (l *LanguageService) GetSymbolDocumentationComment(c *checker.Checker, symbol *ast.Symbol) string {
|
||||
if symbol == nil {
|
||||
return ""
|
||||
}
|
||||
var parts []string
|
||||
var seen collections.Set[*ast.Node]
|
||||
for _, decl := range symbol.Declarations {
|
||||
if decl == nil {
|
||||
continue
|
||||
}
|
||||
if !seen.AddIfAbsent(decl) {
|
||||
continue
|
||||
}
|
||||
if doc := l.getDocumentationFromDeclaration(c, symbol, decl, decl, lsproto.MarkupKindPlainText, true /*commentOnly*/); doc != "" && !slices.Contains(parts, doc) {
|
||||
parts = append(parts, doc)
|
||||
}
|
||||
}
|
||||
return strings.Join(parts, "\n")
|
||||
}
|
||||
|
||||
// GetSymbolJSDocTags collects a symbol's JSDoc tags. It backs the API's Symbol.getJsDocTags
|
||||
// and mirrors Strada's getJsDocTagsFromDeclarations, except each tag's text is rendered as a
|
||||
// plain string rather than SymbolDisplayPart[]. Tags with no text have an empty Text field.
|
||||
func (l *LanguageService) GetSymbolJSDocTags(symbol *ast.Symbol) []JSDocTagInfo {
|
||||
if symbol == nil {
|
||||
return nil
|
||||
}
|
||||
var infos []JSDocTagInfo
|
||||
var seen collections.Set[*ast.Node]
|
||||
for _, decl := range symbol.Declarations {
|
||||
if decl == nil {
|
||||
continue
|
||||
}
|
||||
if !seen.AddIfAbsent(decl) {
|
||||
continue
|
||||
}
|
||||
tags := declarationJSDocTags(decl)
|
||||
// Skip comments containing @typedef/@callback since they're not associated with a
|
||||
// particular declaration, unless they also carry @param/@return (treated as local docs).
|
||||
hasTypedef := core.Some(tags, func(t *ast.Node) bool {
|
||||
return t.Kind == ast.KindJSDocTypedefTag || t.Kind == ast.KindJSDocCallbackTag
|
||||
})
|
||||
hasParamOrReturn := core.Some(tags, func(t *ast.Node) bool {
|
||||
return t.Kind == ast.KindJSDocParameterTag || t.Kind == ast.KindJSDocReturnTag
|
||||
})
|
||||
if hasTypedef && !hasParamOrReturn {
|
||||
continue
|
||||
}
|
||||
for _, tag := range tags {
|
||||
infos = append(infos, JSDocTagInfo{Name: tag.TagName().Text(), Text: getJSDocTagText(tag)})
|
||||
}
|
||||
}
|
||||
return infos
|
||||
}
|
||||
|
||||
// declarationJSDocTags returns the JSDoc tags associated with a declaration, walking the
|
||||
// JSDoc comment location chain like the checker's getAllJSDocTags.
|
||||
func declarationJSDocTags(node *ast.Node) []*ast.Node {
|
||||
if node.Flags&ast.NodeFlagsJSDoc == 0 {
|
||||
for current := node; current != nil; current = ast.GetNextJSDocCommentLocation(current) {
|
||||
jsdocs := current.JSDoc(nil)
|
||||
if len(jsdocs) == 0 {
|
||||
continue
|
||||
}
|
||||
lastJSDoc := jsdocs[len(jsdocs)-1].AsJSDoc()
|
||||
if lastJSDoc.Tags != nil {
|
||||
return lastJSDoc.Tags.Nodes
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getJSDocTagText renders the text of a single JSDoc tag as a plain string, mirroring
|
||||
// Strada's getCommentDisplayParts collapsed from SymbolDisplayPart[] to a string.
|
||||
func getJSDocTagText(tag *ast.Node) string {
|
||||
comment := scanner.GetTextOfJSDocComment(tag.CommentList())
|
||||
addComment := func(s string) string {
|
||||
if comment == "" {
|
||||
return s
|
||||
}
|
||||
return s + " " + comment
|
||||
}
|
||||
switch tag.Kind {
|
||||
case ast.KindJSDocThrowsTag:
|
||||
if te := tag.AsJSDocThrowsTag().TypeExpression; te != nil {
|
||||
return addComment(scanner.GetTextOfNode(te))
|
||||
}
|
||||
return comment
|
||||
case ast.KindJSDocImplementsTag:
|
||||
return addComment(scanner.GetTextOfNode(tag.AsJSDocImplementsTag().ClassName))
|
||||
case ast.KindJSDocAugmentsTag:
|
||||
return addComment(scanner.GetTextOfNode(tag.AsJSDocAugmentsTag().ClassName))
|
||||
case ast.KindJSDocTemplateTag:
|
||||
templateTag := tag.AsJSDocTemplateTag()
|
||||
var b strings.Builder
|
||||
if templateTag.Constraint != nil {
|
||||
b.WriteString(scanner.GetTextOfNode(templateTag.Constraint))
|
||||
}
|
||||
if templateTag.TypeParameters != nil {
|
||||
for i, tp := range templateTag.TypeParameters.Nodes {
|
||||
if i == 0 && b.Len() != 0 {
|
||||
b.WriteString(" ")
|
||||
}
|
||||
if i != 0 {
|
||||
b.WriteString(", ")
|
||||
}
|
||||
b.WriteString(scanner.GetTextOfNode(tp))
|
||||
}
|
||||
}
|
||||
if comment != "" {
|
||||
if b.Len() != 0 {
|
||||
b.WriteString(" ")
|
||||
}
|
||||
b.WriteString(comment)
|
||||
}
|
||||
return b.String()
|
||||
case ast.KindJSDocTypeTag:
|
||||
return addComment(scanner.GetTextOfNode(tag.AsJSDocTypeTag().TypeExpression))
|
||||
case ast.KindJSDocSatisfiesTag:
|
||||
return addComment(scanner.GetTextOfNode(tag.AsJSDocSatisfiesTag().TypeExpression))
|
||||
case ast.KindJSDocSeeTag:
|
||||
if ne := tag.AsJSDocSeeTag().NameExpression; ne != nil {
|
||||
return addComment(scanner.GetTextOfNode(ne))
|
||||
}
|
||||
return comment
|
||||
case ast.KindJSDocParameterTag, ast.KindJSDocPropertyTag:
|
||||
if name := tag.Name(); name != nil {
|
||||
return addComment(scanner.GetTextOfNode(name))
|
||||
}
|
||||
return comment
|
||||
default:
|
||||
return comment
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user