Files
kjol/tools/tsgo/internal/checker/nodebuilder_hover.go
2026-07-09 16:50:43 -04:00

598 lines
24 KiB
Go

package checker
import (
"fmt"
"github.com/microsoft/typescript-go/internal/ast"
"github.com/microsoft/typescript-go/internal/collections"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/jsnum"
"github.com/microsoft/typescript-go/internal/nodebuilder"
"github.com/microsoft/typescript-go/internal/scanner"
)
// isExpanding returns whether the node builder context is operating in hover-expansion mode.
func isExpanding(ctx *NodeBuilderContext) bool {
return ctx.maxExpansionDepth != -1
}
// expandSymbolForHover produces declaration nodes (class, interface, enum, module) for a symbol
// for expandable hover. This is a focused alternative to the full symbolTableToDeclarationStatements
// machinery used by declaration emit — it directly builds the declaration nodes hover needs
// without the declaration-emit scaffolding (deferred privates, symbol name remapping, export
// modifier computation, alias resolution, visited symbols tracking).
func (b *NodeBuilderImpl) expandSymbolForHover(symbol *ast.Symbol) []*ast.Node {
var results []*ast.Node
if symbol.Flags&ast.SymbolFlagsEnum != 0 {
if node := b.expandEnumDecl(symbol); node != nil {
results = append(results, node)
}
}
if symbol.Flags&ast.SymbolFlagsClass != 0 {
if node := b.expandClassDecl(symbol); node != nil {
results = append(results, node)
}
}
// Module/namespace before interface (matching Strada ordering for merged declarations)
if symbol.Flags&(ast.SymbolFlagsValueModule|ast.SymbolFlagsNamespaceModule) != 0 {
if node := b.expandModuleDecl(symbol); node != nil {
results = append(results, node)
}
}
if symbol.Flags&ast.SymbolFlagsInterface != 0 && symbol.Flags&ast.SymbolFlagsClass == 0 {
if node := b.expandInterfaceDecl(symbol); node != nil {
results = append(results, node)
}
}
return results
}
// expandEnumDecl produces an EnumDeclaration node with all members.
func (b *NodeBuilderImpl) expandEnumDecl(symbol *ast.Symbol) *ast.Node {
name := ast.SymbolName(symbol)
b.ctx.approximateLength += 9 + len(name)
memberProps := core.Filter(b.ch.getPropertiesOfType(b.ch.getTypeOfSymbol(symbol)), func(p *ast.Symbol) bool {
return p.Flags&ast.SymbolFlagsEnumMember != 0
})
var members []*ast.Node
for i, p := range memberProps {
if b.checkTruncationLengthIfExpanding() && i+3 < len(memberProps)-1 {
b.ctx.expansionTruncated = true
members = append(members, b.f.NewEnumMember(b.f.NewStringLiteral(fmt.Sprintf(" ... %d more ... ", len(memberProps)-i-1), 0), nil))
last := memberProps[len(memberProps)-1]
members = append(members, b.f.NewEnumMember(b.f.NewIdentifier(last.Name), b.enumMemberInitializer(last)))
break
}
memberDecl := core.Find(p.Declarations, ast.IsEnumMember)
var initializer *ast.Node
if memberDecl != nil && memberDecl.AsEnumMember().Initializer != nil {
initializer = b.f.DeepCloneNode(memberDecl.AsEnumMember().Initializer)
} else {
initializer = b.enumMemberInitializer(p)
}
b.ctx.approximateLength += 4 + len(p.Name)
if initializer != nil {
b.ctx.approximateLength += 5 // " = " + value estimate
}
members = append(members, b.f.NewEnumMember(b.f.NewIdentifier(p.Name), initializer))
}
constModifier := ast.ModifierFlagsNone
if isConstEnumSymbol(symbol) {
constModifier = ast.ModifierFlagsConst
}
var mods *ast.ModifierList
if constModifier != 0 {
mods = b.f.NewModifierList(ast.CreateModifiersFromModifierFlags(constModifier, b.f.NewModifier))
}
return b.f.NewEnumDeclaration(mods, b.f.NewIdentifier(name), b.f.NewNodeList(members))
}
func (b *NodeBuilderImpl) enumMemberInitializer(p *ast.Symbol) *ast.Node {
memberDecl := core.Find(p.Declarations, ast.IsEnumMember)
if memberDecl == nil {
return nil
}
val := b.ch.GetConstantValue(memberDecl)
if val == nil {
return nil
}
switch v := val.(type) {
case string:
return b.f.NewStringLiteral(v, 0)
case jsnum.Number:
return b.f.NewNumericLiteral(v.String(), 0)
}
return nil
}
// expandClassDecl produces a ClassDeclaration node with heritage clauses and members.
func (b *NodeBuilderImpl) expandClassDecl(symbol *ast.Symbol) *ast.Node {
name := ast.SymbolName(symbol)
b.ctx.approximateLength += 9 + len(name)
classLikeDeclarations := core.Filter(symbol.Declarations, ast.IsClassLike)
originalDecl := core.FirstOrNil(classLikeDeclarations)
oldEnclosing := b.ctx.enclosingDeclaration
if originalDecl != nil {
b.ctx.enclosingDeclaration = originalDecl
}
defer func() { b.ctx.enclosingDeclaration = oldEnclosing }()
localParams := b.ch.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)
typeParamDecls := core.Map(localParams, func(p *Type) *ast.Node { return b.typeParameterToDeclaration(p) })
declaredType := b.ch.getDeclaredTypeOfClassOrInterface(symbol)
classType := b.ch.getTypeWithThisArgument(declaredType, nil, false)
baseTypes := b.ch.getBaseTypes(b.ch.getTargetType(classType))
staticType := b.ch.getTypeOfSymbol(symbol)
isClass := staticType.symbol != nil && staticType.symbol.ValueDeclaration != nil && ast.IsClassLike(staticType.symbol.ValueDeclaration)
var staticBaseType *Type
if isClass {
staticBaseType = b.ch.getBaseConstructorTypeOfClass(declaredType)
} else {
staticBaseType = b.ch.anyType
}
// Heritage clauses
heritageClauses := b.hoverHeritageClauses(classLikeDeclarations)
// Instance members via addPropertyToElementList (reusing existing serialization),
// then convert TypeElements to ClassElements and add class-specific modifiers
allProps := b.ch.getPropertiesOfType(classType)
symbolProps := b.filterInheritedProperties(classType, baseTypes, allProps)
publicProps := core.Filter(symbolProps, func(s *ast.Symbol) bool { return !isHashPrivate(s) })
hasPrivate := core.Some(symbolProps, isHashPrivate)
var instanceMembers []*ast.Node
instanceMembers = b.serializePropertiesWithTruncation(publicProps, instanceMembers)
instanceMembers = typeElementsToClassElements(b.f, instanceMembers)
instanceMembers = b.addClassModifiers(instanceMembers, false)
// Static members
staticProps := core.Filter(b.ch.getPropertiesOfType(staticType), func(p *ast.Symbol) bool {
return p.Flags&ast.SymbolFlagsPrototype == 0 && p.Name != "prototype" && !b.isNamespaceMember(p)
})
var staticMembers []*ast.Node
staticMembers = b.serializePropertiesWithTruncation(staticProps, staticMembers)
staticMembers = typeElementsToClassElements(b.f, staticMembers)
staticMembers = b.addClassModifiers(staticMembers, true)
// Hash-private members
var privateMembers []*ast.Node
if hasPrivate {
privateMembers = b.serializePropertiesWithTruncation(core.Filter(symbolProps, isHashPrivate), privateMembers)
privateMembers = typeElementsToClassElements(b.f, privateMembers)
}
// Constructors
constructors := b.serializeConstructors(staticType, staticBaseType, isClass, symbol)
// Index signatures
indexSigs := b.serializeIndexSignaturesOfType(classType, core.FirstOrNil(baseTypes))
allMembers := make([]*ast.Node, 0, len(indexSigs)+len(staticMembers)+len(constructors)+len(instanceMembers)+len(privateMembers))
allMembers = append(allMembers, indexSigs...)
allMembers = append(allMembers, staticMembers...)
allMembers = append(allMembers, constructors...)
allMembers = append(allMembers, instanceMembers...)
allMembers = append(allMembers, privateMembers...)
return b.f.NewClassDeclaration(nil, b.f.NewIdentifier(name), b.f.NewNodeList(typeParamDecls), b.f.NewNodeList(heritageClauses), b.f.NewNodeList(allMembers))
}
// addClassModifiers post-processes class member nodes to add class-specific modifiers
// (private, protected, public, abstract, static) based on the original symbol declarations.
func (b *NodeBuilderImpl) addClassModifiers(members []*ast.Node, isStatic bool) []*ast.Node {
for i, m := range members {
// Find the symbol for this member by matching the property name
var memberSymbol *ast.Symbol
memberName := m.Name()
if memberName != nil {
if sym, ok := b.idToSymbol[memberName]; ok {
memberSymbol = sym
}
}
if memberSymbol == nil {
continue
}
modFlags := getDeclarationModifierFlagsFromSymbol(memberSymbol) &^ ast.ModifierFlagsAsync
if isStatic {
modFlags |= ast.ModifierFlagsStatic
}
if modFlags != 0 && ast.CanHaveModifiers(m) {
existing := m.ModifierFlags()
if modFlags != existing {
members[i] = ast.ReplaceModifiers(b.f, m, b.f.NewModifierList(ast.CreateModifiersFromModifierFlags(modFlags|existing, b.f.NewModifier)))
}
}
}
return members
}
// typeElementsToClassElements converts TypeElement nodes (PropertySignature, MethodSignature)
// to their ClassElement equivalents (PropertyDeclaration, MethodDeclaration) so they can be
// used as members of a ClassDeclaration. Nodes that are already ClassElements pass through unchanged.
func typeElementsToClassElements(f *ast.NodeFactory, members []*ast.Node) []*ast.Node {
for i, m := range members {
switch m.Kind {
case ast.KindPropertySignature:
ps := m.AsPropertySignatureDeclaration()
members[i] = f.NewPropertyDeclaration(m.Modifiers(), ps.Name(), ps.QuestionToken(), ps.Type, nil)
case ast.KindMethodSignature:
ms := m.AsMethodSignatureDeclaration()
members[i] = f.NewMethodDeclaration(m.Modifiers(), nil, ms.Name(), ms.QuestionToken(), ms.TypeParameters, ms.Parameters, ms.Type, nil, nil)
}
}
return members
}
// expandInterfaceDecl produces an InterfaceDeclaration with members.
// Reuses addPropertyToElementList for property serialization and
// signatureToSignatureDeclarationHelper for signatures.
func (b *NodeBuilderImpl) expandInterfaceDecl(symbol *ast.Symbol) *ast.Node {
name := ast.SymbolName(symbol)
b.ctx.approximateLength += 14 + len(name)
interfaceType := b.ch.getDeclaredTypeOfClassOrInterface(symbol)
interfaceDeclarations := core.Filter(symbol.Declarations, ast.IsInterfaceDeclaration)
localParams := b.ch.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)
typeParamDecls := core.Map(localParams, func(p *Type) *ast.Node { return b.typeParameterToDeclaration(p) })
baseTypes := b.ch.getBaseTypes(interfaceType)
var baseType *Type
if len(baseTypes) > 0 {
baseType = b.ch.getIntersectionType(baseTypes)
}
// Members: reuse existing serialization functions
resolved := b.ch.resolveStructuredTypeMembers(interfaceType)
var members []*ast.Node
// Index signatures, filtering those identical to base
members = append(members, b.serializeIndexSignaturesOfType(interfaceType, baseType)...)
// Construct signatures (skip abstract)
for _, sig := range resolved.ConstructSignatures() {
if sig.flags&SignatureFlagsAbstract != 0 {
continue
}
members = append(members, b.signatureToSignatureDeclarationHelper(sig, ast.KindConstructSignature, nil))
}
// Call signatures
for _, sig := range resolved.CallSignatures() {
members = append(members, b.signatureToSignatureDeclarationHelper(sig, ast.KindCallSignature, nil))
}
// Properties, filtering inherited
filteredProps := b.filterInheritedProperties(interfaceType, baseTypes, resolved.properties)
members = b.serializePropertiesWithTruncation(filteredProps, members)
// Heritage clauses
heritageClauses := b.hoverHeritageClauses(interfaceDeclarations)
return b.f.NewInterfaceDeclaration(nil, b.f.NewIdentifier(name), b.f.NewNodeList(typeParamDecls), b.f.NewNodeList(heritageClauses), b.f.NewNodeList(members))
}
func (b *NodeBuilderImpl) hoverHeritageClauses(declarations []*ast.Node) []*ast.Node {
var extendsTypes []*ast.Node
var implementsTypes []*ast.Node
for _, declaration := range declarations {
for _, heritageElement := range ast.GetExtendsHeritageClauseElements(declaration) {
extendsTypes = append(extendsTypes, b.f.DeepCloneNode(heritageElement.AsNode()))
}
for _, heritageElement := range ast.GetImplementsHeritageClauseElements(declaration) {
implementsTypes = append(implementsTypes, b.f.DeepCloneNode(heritageElement.AsNode()))
}
}
var heritageClauses []*ast.Node
if len(extendsTypes) > 0 {
heritageClauses = append(heritageClauses, b.f.NewHeritageClause(ast.KindExtendsKeyword, b.f.NewNodeList(extendsTypes)))
}
if len(implementsTypes) > 0 {
heritageClauses = append(heritageClauses, b.f.NewHeritageClause(ast.KindImplementsKeyword, b.f.NewNodeList(implementsTypes)))
}
return heritageClauses
}
// serializePropertiesWithTruncation iterates properties using addPropertyToElementList,
// with truncation checks matching Strada's createTypeNodesFromResolvedType behavior.
func (b *NodeBuilderImpl) serializePropertiesWithTruncation(properties []*ast.Symbol, elements []*ast.Node) []*ast.Node {
properties = core.Filter(properties, func(p *ast.Symbol) bool {
return p.Flags&ast.SymbolFlagsPrototype == 0
})
for i, p := range properties {
if b.checkTruncationLengthIfExpanding() && (i+3 < len(properties)-1) {
b.ctx.expansionTruncated = true
text := fmt.Sprintf("... %d more ...", len(properties)-i-1)
elements = append(elements, b.f.NewPropertySignatureDeclaration(nil, b.f.NewIdentifier(text), nil, nil, nil))
elements = b.addPropertyToElementList(properties[len(properties)-1], elements)
break
}
elements = b.addPropertyToElementList(p, elements)
}
return elements
}
// serializeConstructors builds constructor signature(s) for a class, with base type filtering.
func (b *NodeBuilderImpl) serializeConstructors(staticType *Type, staticBaseType *Type, isClass bool, symbol *ast.Symbol) []*ast.Node {
isNonConstructable := !isClass &&
symbol.ValueDeclaration != nil &&
ast.IsInJSFile(symbol.ValueDeclaration) &&
len(b.ch.getSignaturesOfType(staticType, SignatureKindConstruct)) == 0
if isNonConstructable {
b.ctx.approximateLength += 21
modifiers := ast.CreateModifiersFromModifierFlags(ast.ModifierFlagsPrivate, b.f.NewModifier)
return []*ast.Node{b.f.NewConstructorDeclaration(b.f.NewModifierList(modifiers), nil, b.f.NewNodeList(nil), nil, nil, nil)}
}
signatures := b.ch.getSignaturesOfType(staticType, SignatureKindConstruct)
if staticBaseType != nil {
baseSigs := b.ch.getSignaturesOfType(staticBaseType, SignatureKindConstruct)
if len(baseSigs) == 0 && core.Every(signatures, func(sig *Signature) bool { return len(sig.parameters) == 0 }) {
return nil
}
if len(baseSigs) == len(signatures) {
allMatch := true
for i := range baseSigs {
if b.ch.compareSignaturesIdentical(signatures[i], baseSigs[i], false, false, true, b.ch.compareTypesIdentical) != TernaryTrue {
allMatch = false
break
}
}
if allMatch {
return nil
}
}
var privateProtected ast.ModifierFlags
for _, sig := range signatures {
if sig.declaration != nil {
privateProtected |= sig.declaration.ModifierFlags() & (ast.ModifierFlagsPrivate | ast.ModifierFlagsProtected)
}
}
if privateProtected != 0 {
return []*ast.Node{b.f.NewConstructorDeclaration(
b.f.NewModifierList(ast.CreateModifiersFromModifierFlags(privateProtected, b.f.NewModifier)),
nil, b.f.NewNodeList(nil), nil, nil, nil,
)}
}
} else if core.Every(signatures, func(sig *Signature) bool { return len(sig.parameters) == 0 }) {
return nil
}
var result []*ast.Node
for _, sig := range signatures {
b.ctx.approximateLength++
result = append(result, b.signatureToSignatureDeclarationHelper(sig, ast.KindConstructor, nil))
}
return result
}
// serializeIndexSignaturesOfType builds index signature declarations, filtering those identical to baseType.
func (b *NodeBuilderImpl) serializeIndexSignaturesOfType(input *Type, baseType *Type) []*ast.Node {
var result []*ast.Node
for _, info := range b.ch.getIndexInfosOfType(input) {
if baseType != nil {
baseInfo := b.ch.getIndexInfoOfType(baseType, info.keyType)
if baseInfo != nil && b.ch.isTypeIdenticalTo(info.valueType, baseInfo.valueType) {
continue
}
}
result = append(result, b.indexInfoToIndexSignatureDeclarationHelper(info, nil))
}
return result
}
// serializeNamespaceMember produces the appropriate declaration node for a namespace member
// based on its symbol flags (type alias, enum, class, interface, nested namespace, or variable).
func (b *NodeBuilderImpl) serializeNamespaceMember(resolved *ast.Symbol, name string) *ast.Node {
switch {
case resolved.Flags&ast.SymbolFlagsTypeAlias != 0:
return b.serializeTypeAliasForNamespace(resolved, name)
case resolved.Flags&ast.SymbolFlagsEnum != 0:
return b.expandEnumDecl(resolved)
case resolved.Flags&ast.SymbolFlagsClass != 0:
return b.expandClassDecl(resolved)
case resolved.Flags&ast.SymbolFlagsInterface != 0:
return b.expandInterfaceDecl(resolved)
case resolved.Flags&(ast.SymbolFlagsValueModule|ast.SymbolFlagsNamespaceModule) != 0:
return b.expandModuleDecl(resolved)
default:
t := b.ch.getWidenedType(b.ch.getTypeOfSymbol(resolved))
b.ctx.approximateLength += len(name) + 5
return b.f.NewVariableStatement(
nil,
b.f.NewVariableDeclarationList(
b.f.NewNodeList([]*ast.Node{
b.f.NewVariableDeclaration(b.f.NewIdentifier(name), nil, b.serializeTypeForDeclaration(nil, t, resolved, true), nil),
}),
ast.NodeFlagsLet,
),
)
}
}
// expandModuleDecl produces a ModuleDeclaration with exported members.
func (b *NodeBuilderImpl) expandModuleDecl(symbol *ast.Symbol) *ast.Node {
exports := b.ch.getExportsOfSymbol(symbol)
var members []*ast.Symbol
for _, sym := range exports {
// Filter to namespace-relevant members
if !b.isNamespaceMember(sym) {
continue
}
if !scanner.IsIdentifierText(sym.Name, core.LanguageVariantStandard) {
continue
}
members = append(members, sym)
}
b.ch.sortSymbols(members)
b.ctx.approximateLength += 14
// Use the same name as symbol display.
oldFlags := b.ctx.flags
defer func() { b.ctx.flags = oldFlags }()
b.ctx.flags |= nodebuilder.FlagsWriteTypeParametersInQualifiedName | nodebuilder.Flags(SymbolFormatFlagsUseOnlyExternalAliasing)
localName := b.symbolToNode(symbol, ast.SymbolFlagsAll)
b.ctx.flags = oldFlags
type hoverStatement struct {
node *ast.Node
isLocal bool // local declarations (e.g. alias targets) should not get export modifier
}
var bodyStmts []hoverStatement
var emittedLocals collections.Set[*ast.Symbol]
for i := 0; i < len(members); i++ {
m := members[i]
if b.checkTruncationLengthIfExpanding() && i+3 < len(members)-1 {
b.ctx.expansionTruncated = true
bodyStmts = append(bodyStmts, hoverStatement{node: b.f.NewExpressionStatement(b.f.NewIdentifier(fmt.Sprintf("... (%d more) ...", len(members)-i-1)))})
i = len(members) - 2 // skip to last member after i++ at end of iteration
continue
}
// Handle alias/re-export symbols
if m.Flags&ast.SymbolFlagsAlias != 0 {
aliasDecl := b.ch.getDeclarationOfAliasSymbol(m)
target := b.ch.getMergedSymbol(b.ch.getTargetOfAliasDeclaration(aliasDecl))
if target != nil {
// If the alias target is a local symbol (not itself an export), emit its declaration first
if target.Flags&(ast.SymbolFlagsBlockScopedVariable|ast.SymbolFlagsFunctionScopedVariable|ast.SymbolFlagsProperty) != 0 {
if emittedLocals.AddIfAbsent(target) {
localType := b.ch.getWidenedType(b.ch.getTypeOfSymbol(target))
b.ctx.approximateLength += len(target.Name) + 5
localStmt := b.f.NewVariableStatement(nil,
b.f.NewVariableDeclarationList(b.f.NewNodeList([]*ast.Node{
b.f.NewVariableDeclaration(b.f.NewIdentifier(target.Name), nil, b.serializeTypeForDeclaration(nil, localType, target, true), nil),
}), ast.NodeFlagsLet))
bodyStmts = append(bodyStmts, hoverStatement{node: localStmt, isLocal: true})
}
}
targetName := target.Name
b.ctx.approximateLength += 16 + len(m.Name)
var propertyName *ast.Node
if m.Name != targetName {
propertyName = b.f.NewIdentifier(targetName)
}
stmt := b.f.NewExportDeclaration(
nil, false,
b.f.NewNamedExports(b.f.NewNodeList([]*ast.Node{
b.f.NewExportSpecifier(false, propertyName, b.f.NewIdentifier(m.Name)),
})),
nil, nil,
)
bodyStmts = append(bodyStmts, hoverStatement{node: stmt})
continue
}
}
resolved := b.ch.resolveSymbol(m)
// Handle functions as function declarations
if resolved.Flags&(ast.SymbolFlagsFunction|ast.SymbolFlagsMethod) != 0 {
t := b.ch.getTypeOfSymbol(resolved)
sigs := b.ch.getSignaturesOfType(t, SignatureKindCall)
for _, sig := range sigs {
b.ctx.approximateLength++
decl := b.signatureToSignatureDeclarationHelper(sig, ast.KindFunctionDeclaration, &SignatureToSignatureDeclarationOptions{
name: b.f.NewIdentifier(m.Name),
})
bodyStmts = append(bodyStmts, hoverStatement{node: decl})
}
// If the function also has namespace characteristics, emit an empty namespace.
merged := b.ch.getMergedSymbol(resolved)
hasModuleExports := merged.Flags&(ast.SymbolFlagsValueModule|ast.SymbolFlagsNamespaceModule) != 0 && merged.Exports != nil && len(merged.Exports) != 0
if !hasModuleExports {
bodyStmts = append(bodyStmts, hoverStatement{node: b.f.NewModuleDeclaration(nil, ast.KindNamespaceKeyword, b.f.NewIdentifier(m.Name), b.f.NewModuleBlock(b.f.NewNodeList(nil)))})
}
continue
}
// Handle remaining member kinds (type alias, enum, class, interface, namespace, variable)
if node := b.serializeNamespaceMember(resolved, m.Name); node != nil {
bodyStmts = append(bodyStmts, hoverStatement{node: node})
}
}
// Add export modifier to exported statements (skip local declarations and ExportDeclarations).
for i := range bodyStmts {
s := &bodyStmts[i]
if s.isLocal || ast.IsExportDeclaration(s.node) {
continue
}
if ast.CanHaveModifiers(s.node) {
mf := s.node.ModifierFlags() | ast.ModifierFlagsExport
s.node = ast.ReplaceModifiers(b.f, s.node, b.f.NewModifierList(ast.CreateModifiersFromModifierFlags(mf, b.f.NewModifier)))
}
}
// Collect nodes, stripping export if all statements are exported.
bodyStatements := make([]*ast.Node, len(bodyStmts))
for i := range bodyStmts {
bodyStatements[i] = bodyStmts[i].node
}
allExported := len(bodyStatements) > 0 && core.Every(bodyStatements, func(d *ast.Node) bool {
return ast.HasSyntacticModifier(d, ast.ModifierFlagsExport)
})
if allExported {
for i, stmt := range bodyStatements {
if ast.CanHaveModifiers(stmt) {
mf := stmt.ModifierFlags() &^ ast.ModifierFlagsExport
bodyStatements[i] = ast.ReplaceModifiers(b.f, stmt, b.f.NewModifierList(ast.CreateModifiersFromModifierFlags(mf, b.f.NewModifier)))
}
}
}
keyword := ast.KindNamespaceKeyword
if !ast.IsIdentifier(localName) {
keyword = ast.KindModuleKeyword
}
return b.f.NewModuleDeclaration(nil, keyword, localName, b.f.NewModuleBlock(b.f.NewNodeList(bodyStatements)))
}
// serializeTypeAliasForNamespace produces a TypeAliasDeclaration for a type alias inside a namespace body.
func (b *NodeBuilderImpl) serializeTypeAliasForNamespace(symbol *ast.Symbol, name string) *ast.Node {
aliasType := b.ch.getDeclaredTypeOfTypeAlias(symbol)
typeParams := b.ch.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)
typeParamDecls := core.Map(typeParams, func(p *Type) *ast.Node { return b.typeParameterToDeclaration(p) })
restoreFlags := b.saveRestoreFlags()
b.ctx.flags |= nodebuilder.FlagsInTypeAlias
typeNode := b.typeToTypeNode(aliasType)
restoreFlags()
b.ctx.approximateLength += 8 + len(name)
return b.f.NewTypeAliasDeclaration(nil, b.f.NewIdentifier(name), b.f.NewNodeList(typeParamDecls), typeNode)
}
// filterInheritedProperties removes properties already present in base types.
func (b *NodeBuilderImpl) filterInheritedProperties(t *Type, baseTypes []*Type, properties []*ast.Symbol) []*ast.Symbol {
if len(baseTypes) == 0 {
return properties
}
// Build a lookup from property name to symbol for parent-identity comparison.
propsByName := make(map[string]*ast.Symbol, len(properties))
for _, p := range properties {
propsByName[p.Name] = p
}
// Collect names of properties inherited unchanged from base types.
var inherited collections.Set[string]
for _, base := range baseTypes {
baseWithThis := b.ch.getTypeWithThisArgument(base, b.ch.getTargetType(t).AsInterfaceType().thisType, false)
for _, prop := range b.ch.getPropertiesOfType(baseWithThis) {
if existing, ok := propsByName[prop.Name]; ok && prop.Parent == existing.Parent {
inherited.Add(prop.Name)
}
}
}
if inherited.Len() == 0 {
return properties
}
return core.Filter(properties, func(p *ast.Symbol) bool {
return !inherited.Has(p.Name)
})
}
func (b *NodeBuilderImpl) isNamespaceMember(p *ast.Symbol) bool {
return p.Flags&(ast.SymbolFlagsType|ast.SymbolFlagsNamespace|ast.SymbolFlagsAlias) != 0 ||
!(p.Flags&ast.SymbolFlagsPrototype != 0 || p.Name == "prototype" || (p.ValueDeclaration != nil && ast.HasStaticModifier(p.ValueDeclaration) && ast.IsClassLike(p.ValueDeclaration.Parent)))
}
func isHashPrivate(s *ast.Symbol) bool {
return s.ValueDeclaration != nil && s.ValueDeclaration.Name() != nil && ast.IsPrivateIdentifier(s.ValueDeclaration.Name())
}