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

3060 lines
94 KiB
Go

package ast
import (
"fmt"
"iter"
"strings"
"sync"
"sync/atomic"
"github.com/microsoft/typescript-go/internal/collections"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/stringutil"
"github.com/microsoft/typescript-go/internal/tspath"
"github.com/zeebo/xxh3"
)
// parseJSDocForNode is the package-level function for lazily parsing JSDoc.
// It is set by the parser package via init().
var parseJSDocForNode func(*SourceFile, *Node) []*Node
// SetParseJSDocForNode registers the lazy JSDoc parse function. Called from parser's init().
func SetParseJSDocForNode(fn func(*SourceFile, *Node) []*Node) {
parseJSDocForNode = fn
}
// Visitor
type Visitor func(*Node) bool
func visit(v Visitor, node *Node) bool {
if node != nil {
return v(node)
}
return false
}
func visitNodes(v Visitor, nodes []*Node) bool {
for _, node := range nodes { //nolint:modernize
if v(node) {
return true
}
}
return false
}
func visitNodeList(v Visitor, nodeList *NodeList) bool {
if nodeList != nil {
return visitNodes(v, nodeList.Nodes)
}
return false
}
func visitModifiers(v Visitor, modifiers *ModifierList) bool {
if modifiers != nil {
return visitNodes(v, modifiers.Nodes)
}
return false
}
type NodeFactoryHooks struct {
OnCreate func(node *Node) // Hooks the creation of a node.
OnUpdate func(node *Node, original *Node) // Hooks the updating of a node.
OnClone func(node *Node, original *Node) // Hooks the cloning of a node.
}
type NodeFactoryCoercible interface {
AsNodeFactory() *NodeFactory
}
func NewNodeFactory(hooks NodeFactoryHooks) *NodeFactory {
return &NodeFactory{hooks: hooks}
}
func newNode(kind Kind, data nodeData, hooks NodeFactoryHooks) *Node {
n := data.AsNode()
n.Loc = core.UndefinedTextRange()
n.Kind = kind
n.data = data
if hooks.OnCreate != nil {
hooks.OnCreate(n)
}
return n
}
func (f *NodeFactory) newNode(kind Kind, data nodeData) *Node {
f.nodeCount++
return newNode(kind, data, f.hooks)
}
func (f *NodeFactory) NodeCount() int {
return f.nodeCount
}
func (f *NodeFactory) TextCount() int {
return f.textCount
}
func (f *NodeFactory) AsNodeFactory() *NodeFactory {
return f
}
func updateNode(updated *Node, original *Node, hooks NodeFactoryHooks) *Node {
if updated != original {
updated.Flags = original.Flags
updated.Loc = original.Loc
if hooks.OnUpdate != nil {
hooks.OnUpdate(updated, original)
}
}
return updated
}
func cloneNode(updated *Node, original *Node, hooks NodeFactoryHooks) *Node {
updateNode(updated, original, hooks)
if updated != original && hooks.OnClone != nil {
hooks.OnClone(updated, original)
}
return updated
}
// NodeList
type NodeList struct {
Loc core.TextRange
Nodes []*Node
}
func (f *NodeFactory) NewNodeList(nodes []*Node) *NodeList {
list := f.nodeListArena.New()
list.Loc = core.UndefinedTextRange()
list.Nodes = nodes
return list
}
func (list *NodeList) Pos() int { return list.Loc.Pos() }
func (list *NodeList) End() int { return list.Loc.End() }
func (list *NodeList) HasTrailingComma() bool {
if len(list.Nodes) == 0 {
return false
}
last := list.Nodes[len(list.Nodes)-1]
return last.End() < list.End()
}
func (list *NodeList) Clone(f NodeFactoryCoercible) *NodeList {
result := f.AsNodeFactory().NewNodeList(list.Nodes)
result.Loc = list.Loc
return result
}
// ModifierList
type ModifierList struct {
NodeList
ModifierFlags ModifierFlags
}
func (f *NodeFactory) NewModifierList(nodes []*Node) *ModifierList {
list := f.modifierListArena.New()
list.Loc = core.UndefinedTextRange()
list.Nodes = nodes
list.ModifierFlags = ModifiersToFlags(nodes)
return list
}
func (list *ModifierList) Clone(f *NodeFactory) *ModifierList {
res := f.modifierListArena.New()
res.Loc = list.Loc
res.Nodes = list.Nodes
res.ModifierFlags = list.ModifierFlags
return res
}
// AST Node
// Interface values stored in AST nodes are never typed nil values. Construction code must ensure that
// interface valued properties either store a true nil or a reference to a non-nil struct.
type Node struct {
Kind Kind
Flags NodeFlags
Loc core.TextRange
id atomic.Uint64
Parent *Node
data nodeData
}
// Node accessors. Some accessors are implemented as methods on NodeData, others are implemented though
// type switches. Either approach is fine. Interface methods are likely more performant, but have higher
// code size costs because we have hundreds of implementations of the NodeData interface.
func (n *Node) AsNode() *Node { return n }
func (n *Node) Pos() int { return n.Loc.Pos() }
func (n *Node) End() int { return n.Loc.End() }
func (n *Node) IterChildren() iter.Seq[*Node] {
// Implemented directly (rather than through the nodeData interface) so that the
// returned iterator and the visitor closure it passes to ForEachChild do not
// escape: an interface call is opaque to escape analysis. `true` stops a TS
// visitor early, whereas `false` stops a Go iterator yield, so the result is
// inverted.
return func(yield func(*Node) bool) {
n.ForEachChild(func(child *Node) bool {
return !yield(child)
})
}
}
func (n *Node) Clone(f NodeFactoryCoercible) *Node { return n.data.Clone(f) }
func (n *Node) VisitEachChild(v *NodeVisitor) *Node { return n.data.VisitEachChild(v) }
func (n *Node) Name() *DeclarationName { return n.data.Name() }
func (n *Node) Modifiers() *ModifierList { return n.data.Modifiers() }
func (n *Node) FlowNodeData() *FlowNodeBase { return n.data.FlowNodeData() }
func (n *Node) DeclarationData() *DeclarationBase { return n.data.DeclarationData() }
func (n *Node) ExportableData() *ExportableBase { return n.data.ExportableData() }
func (n *Node) LocalsContainerData() *LocalsContainerBase { return n.data.LocalsContainerData() }
func (n *Node) FunctionLikeData() *FunctionLikeBase { return n.data.FunctionLikeData() }
func (n *Node) ParameterList() *ParameterList { return n.data.FunctionLikeData().Parameters }
func (n *Node) Parameters() []*ParameterDeclarationNode { return n.ParameterList().Nodes }
func (n *Node) ClassLikeData() *ClassLikeBase { return n.data.ClassLikeData() }
func (n *Node) BodyData() *BodyBase { return n.data.BodyData() }
func (n *Node) SubtreeFacts() SubtreeFacts { return n.data.SubtreeFacts() }
func (n *Node) propagateSubtreeFacts() SubtreeFacts { return n.data.propagateSubtreeFacts() }
func (n *Node) LiteralLikeData() *LiteralLikeNodeBase { return n.data.LiteralLikeData() }
func (n *Node) TemplateLiteralLikeData() *TemplateLiteralLikeNodeBase {
return n.data.TemplateLiteralLikeData()
}
func (n *Node) KindString() string { return n.Kind.String() }
func (n *Node) KindValue() int16 { return int16(n.Kind) }
func (n *Node) Decorators() []*Node {
if n.Modifiers() == nil {
return nil
}
return core.Filter(n.Modifiers().Nodes, IsDecorator)
}
type MutableNode Node
func (n *Node) AsMutable() *MutableNode { return (*MutableNode)(n) }
func (n *MutableNode) SetModifiers(modifiers *ModifierList) { n.data.setModifiers(modifiers) }
func (n *Node) Symbol() *Symbol {
data := n.DeclarationData()
if data != nil {
return data.Symbol
}
return nil
}
func (n *Node) LocalSymbol() *Symbol {
data := n.ExportableData()
if data != nil {
return data.LocalSymbol
}
return nil
}
func (n *Node) Locals() SymbolTable {
data := n.LocalsContainerData()
if data != nil {
return data.Locals
}
return nil
}
func (n *Node) Body() *Node {
data := n.BodyData()
if data != nil {
return data.Body
}
return nil
}
func (n *Node) Text() string {
switch n.Kind {
case KindIdentifier:
return n.AsIdentifier().Text
case KindPrivateIdentifier:
return n.AsPrivateIdentifier().Text
case KindStringLiteral:
return n.AsStringLiteral().Text
case KindNumericLiteral:
return n.AsNumericLiteral().Text
case KindBigIntLiteral:
return n.AsBigIntLiteral().Text
case KindMetaProperty:
return n.AsMetaProperty().Name().Text()
case KindNoSubstitutionTemplateLiteral:
return n.AsNoSubstitutionTemplateLiteral().Text
case KindTemplateHead:
return n.AsTemplateHead().Text
case KindTemplateMiddle:
return n.AsTemplateMiddle().Text
case KindTemplateTail:
return n.AsTemplateTail().Text
case KindJsxNamespacedName:
return n.AsJsxNamespacedName().Namespace.Text() + ":" + n.AsJsxNamespacedName().name.Text()
case KindRegularExpressionLiteral:
return n.AsRegularExpressionLiteral().Text
case KindJSDocText:
return strings.Join(n.AsJSDocText().text, "")
case KindJSDocLink:
return strings.Join(n.AsJSDocLink().text, "")
case KindJSDocLinkCode:
return strings.Join(n.AsJSDocLinkCode().text, "")
case KindJSDocLinkPlain:
return strings.Join(n.AsJSDocLinkPlain().text, "")
}
panic(fmt.Sprintf("Unhandled case in Node.Text: %T", n.data))
}
func (n *Node) Expression() *Node {
switch n.Kind {
case KindPropertyAccessExpression:
return n.AsPropertyAccessExpression().Expression
case KindElementAccessExpression:
return n.AsElementAccessExpression().Expression
case KindParenthesizedExpression:
return n.AsParenthesizedExpression().Expression
case KindCallExpression:
return n.AsCallExpression().Expression
case KindNewExpression:
return n.AsNewExpression().Expression
case KindExpressionWithTypeArguments:
return n.AsExpressionWithTypeArguments().Expression
case KindComputedPropertyName:
return n.AsComputedPropertyName().Expression
case KindNonNullExpression:
return n.AsNonNullExpression().Expression
case KindTypeAssertionExpression:
return n.AsTypeAssertion().Expression
case KindAsExpression:
return n.AsAsExpression().Expression
case KindSatisfiesExpression:
return n.AsSatisfiesExpression().Expression
case KindTypeOfExpression:
return n.AsTypeOfExpression().Expression
case KindSpreadAssignment:
return n.AsSpreadAssignment().Expression
case KindSpreadElement:
return n.AsSpreadElement().Expression
case KindTemplateSpan:
return n.AsTemplateSpan().Expression
case KindDeleteExpression:
return n.AsDeleteExpression().Expression
case KindVoidExpression:
return n.AsVoidExpression().Expression
case KindAwaitExpression:
return n.AsAwaitExpression().Expression
case KindYieldExpression:
return n.AsYieldExpression().Expression
case KindPartiallyEmittedExpression:
return n.AsPartiallyEmittedExpression().Expression
case KindIfStatement:
return n.AsIfStatement().Expression
case KindDoStatement:
return n.AsDoStatement().Expression
case KindWhileStatement:
return n.AsWhileStatement().Expression
case KindWithStatement:
return n.AsWithStatement().Expression
case KindForInStatement, KindForOfStatement:
return n.AsForInOrOfStatement().Expression
case KindSwitchStatement:
return n.AsSwitchStatement().Expression
case KindCaseClause:
return n.AsCaseOrDefaultClause().Expression
case KindExpressionStatement:
return n.AsExpressionStatement().Expression
case KindReturnStatement:
return n.AsReturnStatement().Expression
case KindThrowStatement:
return n.AsThrowStatement().Expression
case KindExternalModuleReference:
return n.AsExternalModuleReference().Expression
case KindExportAssignment:
return n.AsExportAssignment().Expression
case KindDecorator:
return n.AsDecorator().Expression
case KindJsxExpression:
return n.AsJsxExpression().Expression
case KindJsxSpreadAttribute:
return n.AsJsxSpreadAttribute().Expression
}
panic("Unhandled case in Node.Expression: " + n.Kind.String())
}
func (n *Node) RawText() string {
switch n.Kind {
case KindTemplateHead:
return n.AsTemplateHead().RawText
case KindTemplateMiddle:
return n.AsTemplateMiddle().RawText
case KindTemplateTail:
return n.AsTemplateTail().RawText
}
panic("Unhandled case in Node.RawText: " + n.Kind.String())
}
func (m *MutableNode) SetExpression(expr *Node) {
n := (*Node)(m)
switch n.Kind {
case KindPropertyAccessExpression:
n.AsPropertyAccessExpression().Expression = expr
case KindElementAccessExpression:
n.AsElementAccessExpression().Expression = expr
case KindParenthesizedExpression:
n.AsParenthesizedExpression().Expression = expr
case KindCallExpression:
n.AsCallExpression().Expression = expr
case KindNewExpression:
n.AsNewExpression().Expression = expr
case KindExpressionWithTypeArguments:
n.AsExpressionWithTypeArguments().Expression = expr
case KindComputedPropertyName:
n.AsComputedPropertyName().Expression = expr
case KindNonNullExpression:
n.AsNonNullExpression().Expression = expr
case KindTypeAssertionExpression:
n.AsTypeAssertion().Expression = expr
case KindAsExpression:
n.AsAsExpression().Expression = expr
case KindSatisfiesExpression:
n.AsSatisfiesExpression().Expression = expr
case KindTypeOfExpression:
n.AsTypeOfExpression().Expression = expr
case KindSpreadAssignment:
n.AsSpreadAssignment().Expression = expr
case KindSpreadElement:
n.AsSpreadElement().Expression = expr
case KindTemplateSpan:
n.AsTemplateSpan().Expression = expr
case KindDeleteExpression:
n.AsDeleteExpression().Expression = expr
case KindVoidExpression:
n.AsVoidExpression().Expression = expr
case KindAwaitExpression:
n.AsAwaitExpression().Expression = expr
case KindYieldExpression:
n.AsYieldExpression().Expression = expr
case KindPartiallyEmittedExpression:
n.AsPartiallyEmittedExpression().Expression = expr
case KindIfStatement:
n.AsIfStatement().Expression = expr
case KindDoStatement:
n.AsDoStatement().Expression = expr
case KindWhileStatement:
n.AsWhileStatement().Expression = expr
case KindWithStatement:
n.AsWithStatement().Expression = expr
case KindForInStatement, KindForOfStatement:
n.AsForInOrOfStatement().Expression = expr
case KindSwitchStatement:
n.AsSwitchStatement().Expression = expr
case KindCaseClause:
n.AsCaseOrDefaultClause().Expression = expr
case KindExpressionStatement:
n.AsExpressionStatement().Expression = expr
case KindReturnStatement:
n.AsReturnStatement().Expression = expr
case KindThrowStatement:
n.AsThrowStatement().Expression = expr
case KindExternalModuleReference:
n.AsExternalModuleReference().Expression = expr
case KindExportAssignment:
n.AsExportAssignment().Expression = expr
case KindDecorator:
n.AsDecorator().Expression = expr
case KindJsxExpression:
n.AsJsxExpression().Expression = expr
case KindJsxSpreadAttribute:
n.AsJsxSpreadAttribute().Expression = expr
default:
panic("Unhandled case in mutableNode.SetExpression: " + n.Kind.String())
}
}
func (n *Node) ArgumentList() *NodeList {
switch n.Kind {
case KindCallExpression:
return n.AsCallExpression().Arguments
case KindNewExpression:
return n.AsNewExpression().Arguments
}
panic("Unhandled case in Node.Arguments: " + n.Kind.String())
}
func (n *Node) Arguments() []*Node {
list := n.ArgumentList()
if list != nil {
return list.Nodes
}
return nil
}
func (n *Node) TypeArgumentList() *NodeList {
switch n.Kind {
case KindCallExpression:
return n.AsCallExpression().TypeArguments
case KindNewExpression:
return n.AsNewExpression().TypeArguments
case KindTaggedTemplateExpression:
return n.AsTaggedTemplateExpression().TypeArguments
case KindTypeReference:
return n.AsTypeReferenceNode().TypeArguments
case KindExpressionWithTypeArguments:
return n.AsExpressionWithTypeArguments().TypeArguments
case KindImportType:
return n.AsImportTypeNode().TypeArguments
case KindTypeQuery:
return n.AsTypeQueryNode().TypeArguments
case KindJsxOpeningElement:
return n.AsJsxOpeningElement().TypeArguments
case KindJsxSelfClosingElement:
return n.AsJsxSelfClosingElement().TypeArguments
}
panic("Unhandled case in Node.TypeArguments")
}
func (n *Node) TypeArguments() []*Node {
list := n.TypeArgumentList()
if list != nil {
return list.Nodes
}
return nil
}
func (n *Node) TypeParameterList() *NodeList {
switch n.Kind {
case KindClassDeclaration:
return n.AsClassDeclaration().TypeParameters
case KindClassExpression:
return n.AsClassExpression().TypeParameters
case KindInterfaceDeclaration:
return n.AsInterfaceDeclaration().TypeParameters
case KindTypeAliasDeclaration, KindJSTypeAliasDeclaration:
return n.AsTypeAliasDeclaration().TypeParameters
case KindJSDocTemplateTag:
return n.AsJSDocTemplateTag().TypeParameters
default:
funcLike := n.FunctionLikeData()
if funcLike != nil {
return funcLike.TypeParameters
}
}
panic("Unhandled case in Node.TypeParameterList")
}
func (n *Node) TypeParameters() []*Node {
list := n.TypeParameterList()
if list != nil {
return list.Nodes
}
return nil
}
func (n *Node) MemberList() *NodeList {
switch n.Kind {
case KindClassDeclaration:
return n.AsClassDeclaration().Members
case KindClassExpression:
return n.AsClassExpression().Members
case KindInterfaceDeclaration:
return n.AsInterfaceDeclaration().Members
case KindEnumDeclaration:
return n.AsEnumDeclaration().Members
case KindTypeLiteral:
return n.AsTypeLiteralNode().Members
case KindMappedType:
return n.AsMappedTypeNode().Members
}
panic("Unhandled case in Node.MemberList: " + n.Kind.String())
}
func (n *Node) Members() []*Node {
list := n.MemberList()
if list != nil {
return list.Nodes
}
return nil
}
func (n *Node) StatementList() *NodeList {
switch n.Kind {
case KindSourceFile:
return n.AsSourceFile().Statements
case KindBlock:
return n.AsBlock().Statements
case KindModuleBlock:
return n.AsModuleBlock().Statements
case KindCaseClause, KindDefaultClause:
return n.AsCaseOrDefaultClause().Statements
}
panic("Unhandled case in Node.StatementList: " + n.Kind.String())
}
func (n *Node) Statements() []*Node {
list := n.StatementList()
if list != nil {
return list.Nodes
}
return nil
}
func (n *Node) CanHaveStatements() bool {
switch n.Kind {
case KindSourceFile, KindBlock, KindModuleBlock, KindCaseClause, KindDefaultClause:
return true
default:
return false
}
}
func (n *Node) ModifierFlags() ModifierFlags {
modifiers := n.Modifiers()
if modifiers != nil {
return modifiers.ModifierFlags
}
return ModifierFlagsNone
}
func (n *Node) ModifierNodes() []*Node {
modifiers := n.Modifiers()
if modifiers != nil {
return modifiers.Nodes
}
return nil
}
func (n *Node) Type() *Node {
switch n.Kind {
case KindVariableDeclaration:
return n.AsVariableDeclaration().Type
case KindParameter:
return n.AsParameterDeclaration().Type
case KindPropertySignature:
return n.AsPropertySignatureDeclaration().Type
case KindPropertyDeclaration:
return n.AsPropertyDeclaration().Type
case KindPropertyAssignment:
return n.AsPropertyAssignment().Type
case KindShorthandPropertyAssignment:
return n.AsShorthandPropertyAssignment().Type
case KindTypePredicate:
return n.AsTypePredicateNode().Type
case KindParenthesizedType:
return n.AsParenthesizedTypeNode().Type
case KindTypeOperator:
return n.AsTypeOperatorNode().Type
case KindMappedType:
return n.AsMappedTypeNode().Type
case KindTypeAssertionExpression:
return n.AsTypeAssertion().Type
case KindAsExpression:
return n.AsAsExpression().Type
case KindSatisfiesExpression:
return n.AsSatisfiesExpression().Type
case KindTypeAliasDeclaration, KindJSTypeAliasDeclaration:
return n.AsTypeAliasDeclaration().Type
case KindNamedTupleMember:
return n.AsNamedTupleMember().Type
case KindOptionalType:
return n.AsOptionalTypeNode().Type
case KindRestType:
return n.AsRestTypeNode().Type
case KindTemplateLiteralTypeSpan:
return n.AsTemplateLiteralTypeSpan().Type
case KindJSDocTypeExpression:
return n.AsJSDocTypeExpression().Type
case KindJSDocParameterTag, KindJSDocPropertyTag:
return n.AsJSDocParameterOrPropertyTag().TypeExpression
case KindJSDocNullableType:
return n.AsJSDocNullableType().Type
case KindJSDocNonNullableType:
return n.AsJSDocNonNullableType().Type
case KindJSDocOptionalType:
return n.AsJSDocOptionalType().Type
case KindExportAssignment:
return n.AsExportAssignment().Type
case KindBinaryExpression:
return n.AsBinaryExpression().Type
default:
if funcLike := n.FunctionLikeData(); funcLike != nil {
return funcLike.Type
}
}
return nil
}
func (m *MutableNode) SetType(t *Node) {
n := (*Node)(m)
switch m.Kind {
case KindVariableDeclaration:
n.AsVariableDeclaration().Type = t
case KindParameter:
n.AsParameterDeclaration().Type = t
case KindPropertySignature:
n.AsPropertySignatureDeclaration().Type = t
case KindPropertyDeclaration:
n.AsPropertyDeclaration().Type = t
case KindPropertyAssignment:
n.AsPropertyAssignment().Type = t
case KindShorthandPropertyAssignment:
n.AsShorthandPropertyAssignment().Type = t
case KindTypePredicate:
n.AsTypePredicateNode().Type = t
case KindParenthesizedType:
n.AsParenthesizedTypeNode().Type = t
case KindTypeOperator:
n.AsTypeOperatorNode().Type = t
case KindMappedType:
n.AsMappedTypeNode().Type = t
case KindTypeAssertionExpression:
n.AsTypeAssertion().Type = t
case KindAsExpression:
n.AsAsExpression().Type = t
case KindSatisfiesExpression:
n.AsSatisfiesExpression().Type = t
case KindTypeAliasDeclaration, KindJSTypeAliasDeclaration:
n.AsTypeAliasDeclaration().Type = t
case KindNamedTupleMember:
n.AsNamedTupleMember().Type = t
case KindOptionalType:
n.AsOptionalTypeNode().Type = t
case KindRestType:
n.AsRestTypeNode().Type = t
case KindTemplateLiteralTypeSpan:
n.AsTemplateLiteralTypeSpan().Type = t
case KindJSDocTypeExpression:
n.AsJSDocTypeExpression().Type = t
case KindJSDocParameterTag, KindJSDocPropertyTag:
n.AsJSDocParameterOrPropertyTag().TypeExpression = t
case KindJSDocNullableType:
n.AsJSDocNullableType().Type = t
case KindJSDocNonNullableType:
n.AsJSDocNonNullableType().Type = t
case KindJSDocOptionalType:
n.AsJSDocOptionalType().Type = t
case KindExportAssignment:
n.AsExportAssignment().Type = t
case KindBinaryExpression:
n.AsBinaryExpression().Type = t
default:
if funcLike := n.FunctionLikeData(); funcLike != nil {
funcLike.Type = t
} else {
panic("Unhandled case in mutableNode.SetType: " + n.Kind.String())
}
}
}
func (n *Node) Initializer() *Node {
switch n.Kind {
case KindVariableDeclaration:
return n.AsVariableDeclaration().Initializer
case KindParameter:
return n.AsParameterDeclaration().Initializer
case KindBindingElement:
return n.AsBindingElement().Initializer
case KindPropertyDeclaration:
return n.AsPropertyDeclaration().Initializer
case KindPropertySignature:
return n.AsPropertySignatureDeclaration().Initializer
case KindPropertyAssignment:
return n.AsPropertyAssignment().Initializer
case KindEnumMember:
return n.AsEnumMember().Initializer
case KindForStatement:
return n.AsForStatement().Initializer
case KindForInStatement, KindForOfStatement:
return n.AsForInOrOfStatement().Initializer
case KindJsxAttribute:
return n.AsJsxAttribute().Initializer
}
panic("Unhandled case in Node.Initializer")
}
func (m *MutableNode) SetInitializer(initializer *Node) {
n := (*Node)(m)
switch n.Kind {
case KindVariableDeclaration:
n.AsVariableDeclaration().Initializer = initializer
case KindParameter:
n.AsParameterDeclaration().Initializer = initializer
case KindBindingElement:
n.AsBindingElement().Initializer = initializer
case KindPropertyDeclaration:
n.AsPropertyDeclaration().Initializer = initializer
case KindPropertySignature:
n.AsPropertySignatureDeclaration().Initializer = initializer
case KindPropertyAssignment:
n.AsPropertyAssignment().Initializer = initializer
case KindEnumMember:
n.AsEnumMember().Initializer = initializer
case KindForStatement:
n.AsForStatement().Initializer = initializer
case KindForInStatement, KindForOfStatement:
n.AsForInOrOfStatement().Initializer = initializer
case KindJsxAttribute:
n.AsJsxAttribute().Initializer = initializer
default:
panic("Unhandled case in mutableNode.SetInitializer")
}
}
func (n *Node) TagName() *Node {
switch n.Kind {
case KindJsxOpeningElement:
return n.AsJsxOpeningElement().TagName
case KindJsxClosingElement:
return n.AsJsxClosingElement().TagName
case KindJsxSelfClosingElement:
return n.AsJsxSelfClosingElement().TagName
case KindJSDocUnknownTag:
return n.AsJSDocUnknownTag().TagName
case KindJSDocAugmentsTag:
return n.AsJSDocAugmentsTag().TagName
case KindJSDocImplementsTag:
return n.AsJSDocImplementsTag().TagName
case KindJSDocDeprecatedTag:
return n.AsJSDocDeprecatedTag().TagName
case KindJSDocPublicTag:
return n.AsJSDocPublicTag().TagName
case KindJSDocPrivateTag:
return n.AsJSDocPrivateTag().TagName
case KindJSDocProtectedTag:
return n.AsJSDocProtectedTag().TagName
case KindJSDocReadonlyTag:
return n.AsJSDocReadonlyTag().TagName
case KindJSDocOverrideTag:
return n.AsJSDocOverrideTag().TagName
case KindJSDocCallbackTag:
return n.AsJSDocCallbackTag().TagName
case KindJSDocOverloadTag:
return n.AsJSDocOverloadTag().TagName
case KindJSDocParameterTag, KindJSDocPropertyTag:
return n.AsJSDocParameterOrPropertyTag().TagName
case KindJSDocReturnTag:
return n.AsJSDocReturnTag().TagName
case KindJSDocThisTag:
return n.AsJSDocThisTag().TagName
case KindJSDocTypeTag:
return n.AsJSDocTypeTag().TagName
case KindJSDocTemplateTag:
return n.AsJSDocTemplateTag().TagName
case KindJSDocTypedefTag:
return n.AsJSDocTypedefTag().TagName
case KindJSDocSeeTag:
return n.AsJSDocSeeTag().TagName
case KindJSDocSatisfiesTag:
return n.AsJSDocSatisfiesTag().TagName
case KindJSDocThrowsTag:
return n.AsJSDocThrowsTag().TagName
case KindJSDocImportTag:
return n.AsJSDocImportTag().TagName
}
panic("Unhandled case in Node.TagName: " + n.Kind.String())
}
func (n *Node) PropertyName() *Node {
switch n.Kind {
case KindImportSpecifier:
return n.AsImportSpecifier().PropertyName
case KindExportSpecifier:
return n.AsExportSpecifier().PropertyName
case KindBindingElement:
return n.AsBindingElement().PropertyName
}
return nil
}
func (n *Node) PropertyNameOrName() *Node {
name := n.PropertyName()
if name == nil {
name = n.Name()
}
return name
}
func (n *Node) IsTypeOnly() bool {
switch n.Kind {
case KindImportEqualsDeclaration:
return n.AsImportEqualsDeclaration().IsTypeOnly
case KindImportSpecifier:
return n.AsImportSpecifier().IsTypeOnly
case KindImportClause:
return n.AsImportClause().PhaseModifier == KindTypeKeyword
case KindExportDeclaration:
return n.AsExportDeclaration().IsTypeOnly
case KindExportSpecifier:
return n.AsExportSpecifier().IsTypeOnly
}
return false
}
// If updating this function, also update `hasComment`.
func (n *Node) CommentList() *NodeList {
switch n.Kind {
case KindJSDoc:
return n.AsJSDoc().Comment
case KindJSDocUnknownTag:
return n.AsJSDocUnknownTag().Comment
case KindJSDocAugmentsTag:
return n.AsJSDocAugmentsTag().Comment
case KindJSDocImplementsTag:
return n.AsJSDocImplementsTag().Comment
case KindJSDocDeprecatedTag:
return n.AsJSDocDeprecatedTag().Comment
case KindJSDocPublicTag:
return n.AsJSDocPublicTag().Comment
case KindJSDocPrivateTag:
return n.AsJSDocPrivateTag().Comment
case KindJSDocProtectedTag:
return n.AsJSDocProtectedTag().Comment
case KindJSDocReadonlyTag:
return n.AsJSDocReadonlyTag().Comment
case KindJSDocOverrideTag:
return n.AsJSDocOverrideTag().Comment
case KindJSDocCallbackTag:
return n.AsJSDocCallbackTag().Comment
case KindJSDocOverloadTag:
return n.AsJSDocOverloadTag().Comment
case KindJSDocParameterTag, KindJSDocPropertyTag:
return n.AsJSDocParameterOrPropertyTag().Comment
case KindJSDocReturnTag:
return n.AsJSDocReturnTag().Comment
case KindJSDocThisTag:
return n.AsJSDocThisTag().Comment
case KindJSDocTypeTag:
return n.AsJSDocTypeTag().Comment
case KindJSDocTemplateTag:
return n.AsJSDocTemplateTag().Comment
case KindJSDocTypedefTag:
return n.AsJSDocTypedefTag().Comment
case KindJSDocSeeTag:
return n.AsJSDocSeeTag().Comment
case KindJSDocSatisfiesTag:
return n.AsJSDocSatisfiesTag().Comment
case KindJSDocThrowsTag:
return n.AsJSDocThrowsTag().Comment
case KindJSDocImportTag:
return n.AsJSDocImportTag().Comment
}
panic("Unhandled case in Node.CommentList: " + n.Kind.String())
}
func (n *Node) Comments() []*Node {
list := n.CommentList()
if list != nil {
return list.Nodes
}
return nil
}
func (n *Node) Label() *Node {
switch n.Kind {
case KindLabeledStatement:
return n.AsLabeledStatement().Label
case KindBreakStatement:
return n.AsBreakStatement().Label
case KindContinueStatement:
return n.AsContinueStatement().Label
}
panic("Unhandled case in Node.Label: " + n.Kind.String())
}
func (n *Node) Attributes() *Node {
switch n.Kind {
case KindJsxOpeningElement:
return n.AsJsxOpeningElement().Attributes
case KindJsxSelfClosingElement:
return n.AsJsxSelfClosingElement().Attributes
}
panic("Unhandled case in Node.Attributes: " + n.Kind.String())
}
func (n *Node) Children() *NodeList {
switch n.Kind {
case KindJsxElement:
return n.AsJsxElement().Children
case KindJsxFragment:
return n.AsJsxFragment().Children
}
panic("Unhandled case in Node.Children: " + n.Kind.String())
}
func (n *Node) ModuleSpecifier() *Expression {
switch n.Kind {
case KindImportDeclaration, KindJSImportDeclaration:
return n.AsImportDeclaration().ModuleSpecifier
case KindExportDeclaration:
return n.AsExportDeclaration().ModuleSpecifier
case KindJSDocImportTag:
return n.AsJSDocImportTag().ModuleSpecifier
}
panic("Unhandled case in Node.ModuleSpecifier: " + n.Kind.String())
}
func (n *Node) ImportClause() *Node {
switch n.Kind {
case KindImportDeclaration, KindJSImportDeclaration:
return n.AsImportDeclaration().ImportClause
case KindJSDocImportTag:
return n.AsJSDocImportTag().ImportClause
}
panic("Unhandled case in Node.ImportClause: " + n.Kind.String())
}
func (n *Node) Statement() *Statement {
switch n.Kind {
case KindDoStatement:
return n.AsDoStatement().Statement
case KindWhileStatement:
return n.AsWhileStatement().Statement
case KindForStatement:
return n.AsForStatement().Statement
case KindForInStatement, KindForOfStatement:
return n.AsForInOrOfStatement().Statement
case KindWithStatement:
return n.AsWithStatement().Statement
case KindLabeledStatement:
return n.AsLabeledStatement().Statement
}
panic("Unhandled case in Node.Statement: " + n.Kind.String())
}
func (n *Node) PropertyList() *NodeList {
switch n.Kind {
case KindObjectLiteralExpression:
return n.AsObjectLiteralExpression().Properties
case KindJsxAttributes:
return n.AsJsxAttributes().Properties
}
panic("Unhandled case in Node.PropertyList: " + n.Kind.String())
}
func (n *Node) Properties() []*Node {
list := n.PropertyList()
if list != nil {
return list.Nodes
}
return nil
}
func (n *Node) ElementList() *NodeList {
switch n.Kind {
case KindNamedImports:
return n.AsNamedImports().Elements
case KindNamedExports:
return n.AsNamedExports().Elements
case KindObjectBindingPattern, KindArrayBindingPattern:
return n.AsBindingPattern().Elements
case KindArrayLiteralExpression:
return n.AsArrayLiteralExpression().Elements
case KindTupleType:
return n.AsTupleTypeNode().Elements
}
panic("Unhandled case in Node.ElementList: " + n.Kind.String())
}
func (n *Node) Elements() []*Node {
list := n.ElementList()
if list != nil {
return list.Nodes
}
return nil
}
func (n *Node) PostfixToken() *Node {
switch n.Kind {
case KindMethodDeclaration:
return n.AsMethodDeclaration().PostfixToken
case KindShorthandPropertyAssignment:
return n.AsShorthandPropertyAssignment().PostfixToken
case KindMethodSignature:
return n.AsMethodSignatureDeclaration().PostfixToken
case KindPropertySignature:
return n.AsPropertySignatureDeclaration().PostfixToken
case KindPropertyAssignment:
return n.AsPropertyAssignment().PostfixToken
case KindPropertyDeclaration:
return n.AsPropertyDeclaration().PostfixToken
case KindEnumMember:
return n.AsEnumMember().PostfixToken
case KindGetAccessor:
return n.AsGetAccessorDeclaration().PostfixToken
case KindSetAccessor:
return n.AsSetAccessorDeclaration().PostfixToken
}
return nil
}
func (n *Node) QuestionToken() *TokenNode {
switch n.Kind {
case KindParameter:
return n.AsParameterDeclaration().QuestionToken
case KindConditionalExpression:
return n.AsConditionalExpression().QuestionToken
case KindMappedType:
return n.AsMappedTypeNode().QuestionToken
case KindNamedTupleMember:
return n.AsNamedTupleMember().QuestionToken
}
postfix := n.PostfixToken()
if postfix != nil && postfix.Kind == KindQuestionToken {
return postfix
}
return nil
}
func (n *Node) QuestionDotToken() *Node {
switch n.Kind {
case KindElementAccessExpression:
return n.AsElementAccessExpression().QuestionDotToken
case KindPropertyAccessExpression:
return n.AsPropertyAccessExpression().QuestionDotToken
case KindCallExpression:
return n.AsCallExpression().QuestionDotToken
case KindTaggedTemplateExpression:
return n.AsTaggedTemplateExpression().QuestionDotToken
}
panic("Unhandled case in Node.QuestionDotToken: " + n.Kind.String())
}
func (n *Node) TypeExpression() *Node {
switch n.Kind {
case KindJSDocParameterTag, KindJSDocPropertyTag:
return n.AsJSDocParameterOrPropertyTag().TypeExpression
case KindJSDocReturnTag:
return n.AsJSDocReturnTag().TypeExpression
case KindJSDocTypeTag:
return n.AsJSDocTypeTag().TypeExpression
case KindJSDocTypedefTag:
return n.AsJSDocTypedefTag().TypeExpression
case KindJSDocCallbackTag:
return n.AsJSDocCallbackTag().TypeExpression
case KindJSDocSatisfiesTag:
return n.AsJSDocSatisfiesTag().TypeExpression
case KindJSDocThrowsTag:
return n.AsJSDocThrowsTag().TypeExpression
}
panic("Unhandled case in Node.TypeExpression: " + n.Kind.String())
}
func (n *Node) ClassName() *Node {
switch n.Kind {
case KindJSDocAugmentsTag:
return n.AsJSDocAugmentsTag().ClassName
case KindJSDocImplementsTag:
return n.AsJSDocImplementsTag().ClassName
}
panic("Unhandled case in Node.ClassName: " + n.Kind.String())
}
// Determines if `n` contains `descendant` by walking up the `Parent` pointers from `descendant`. This method panics if
// `descendant` or one of its ancestors is not parented except when that node is a `SourceFile`.
func (n *Node) Contains(descendant *Node) bool {
for descendant != nil {
if descendant == n {
return true
}
parent := descendant.Parent
if parent == nil && !IsSourceFile(descendant) {
panic("descendant is not parented")
}
descendant = parent
}
return false
}
// Node casts
func (n *Node) AsFlowSwitchClauseData() *FlowSwitchClauseData {
return n.data.(*FlowSwitchClauseData)
}
func (n *Node) AsFlowReduceLabelData() *FlowReduceLabelData {
return n.data.(*FlowReduceLabelData)
}
// NodeData
type nodeData interface {
AsNode() *Node
ForEachChild(v Visitor) bool
VisitEachChild(v *NodeVisitor) *Node
Clone(v NodeFactoryCoercible) *Node
Name() *DeclarationName
Modifiers() *ModifierList
setModifiers(modifiers *ModifierList)
FlowNodeData() *FlowNodeBase
DeclarationData() *DeclarationBase
ExportableData() *ExportableBase
LocalsContainerData() *LocalsContainerBase
FunctionLikeData() *FunctionLikeBase
ClassLikeData() *ClassLikeBase
BodyData() *BodyBase
LiteralLikeData() *LiteralLikeNodeBase
TemplateLiteralLikeData() *TemplateLiteralLikeNodeBase
SubtreeFacts() SubtreeFacts
computeSubtreeFacts() SubtreeFacts
subtreeFactsWorker(self nodeData) SubtreeFacts
propagateSubtreeFacts() SubtreeFacts
}
// NodeDefault
type NodeDefault struct {
Node
}
func (node *NodeDefault) AsNode() *Node { return &node.Node }
func (node *NodeDefault) ForEachChild(v Visitor) bool { return false }
func (node *NodeDefault) VisitEachChild(v *NodeVisitor) *Node { return node.AsNode() }
func (node *NodeDefault) Clone(v NodeFactoryCoercible) *Node { return nil }
func (node *NodeDefault) Name() *DeclarationName { return nil }
func (node *NodeDefault) Modifiers() *ModifierList { return nil }
func (node *NodeDefault) setModifiers(modifiers *ModifierList) {}
func (node *NodeDefault) FlowNodeData() *FlowNodeBase { return nil }
func (node *NodeDefault) DeclarationData() *DeclarationBase { return nil }
func (node *NodeDefault) ExportableData() *ExportableBase { return nil }
func (node *NodeDefault) LocalsContainerData() *LocalsContainerBase { return nil }
func (node *NodeDefault) FunctionLikeData() *FunctionLikeBase { return nil }
func (node *NodeDefault) ClassLikeData() *ClassLikeBase { return nil }
func (node *NodeDefault) BodyData() *BodyBase { return nil }
func (node *NodeDefault) LiteralLikeData() *LiteralLikeNodeBase { return nil }
func (node *NodeDefault) TemplateLiteralLikeData() *TemplateLiteralLikeNodeBase { return nil }
func (node *NodeDefault) SubtreeFacts() SubtreeFacts {
return node.data.subtreeFactsWorker(node.data)
}
func (node *NodeDefault) subtreeFactsWorker(self nodeData) SubtreeFacts {
// To avoid excessive conditional checks, the default implementation of subtreeFactsWorker directly invokes
// computeSubtreeFacts. More complex nodes should implement CompositeNodeBase, which overrides this
// method to cache the result. `self` is passed along to ensure we lookup `computeSubtreeFacts` on the
// correct type, as `CompositeNodeBase` does not, itself, inherit from `Node`.
return self.computeSubtreeFacts()
}
func (node *NodeDefault) computeSubtreeFacts() SubtreeFacts {
return SubtreeFactsNone
}
func (node *NodeDefault) propagateSubtreeFacts() SubtreeFacts {
return node.data.SubtreeFacts() & ^SubtreeExclusionsNode
}
// NodeBase
type NodeBase struct {
NodeDefault
}
// Aliases for Node unions not covered by ast_generated.go
type (
NamedMember = Node // Node with NamedMemberBase
AnyValidImportOrReExport = Node // (ImportDeclaration | ExportDeclaration | JSDocImportTag) & { moduleSpecifier: StringLiteral } | ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteral }} | RequireOrImportCall | ValidImportTypeNode
ValidImportTypeNode = Node // ImportType & { argument: LiteralTypeNode & { literal: StringLiteral } }
TypeOnlyImportDeclaration = Node // ImportClause | ImportEqualsDeclaration | ImportSpecifier | NamespaceImport with isTypeOnly: true
StringLiteralLike = Node // StringLiteral | NoSubstitutionTemplateLiteral
ObjectLiteralLike = Node // ObjectLiteralExpression | ObjectBindingPattern
AnyImportOrRequireStatement = Node // AnyImportSyntax | RequireVariableStatement
)
func IsWriteOnlyAccess(node *Node) bool {
return accessKind(node) == AccessKindWrite
}
func IsWriteAccess(node *Node) bool {
return accessKind(node) != AccessKindRead
}
func IsWriteAccessForReference(node *Node) bool {
decl := GetDeclarationFromName(node)
return (decl != nil && declarationIsWriteAccess(decl)) || node.Kind == KindDefaultKeyword || IsWriteAccess(node)
}
func GetDeclarationFromName(name *Node) *Declaration {
if name == nil || name.Parent == nil {
return nil
}
parent := name.Parent
switch name.Kind {
case KindStringLiteral, KindNoSubstitutionTemplateLiteral, KindNumericLiteral:
if IsComputedPropertyName(parent) {
return parent.Parent
}
fallthrough
case KindIdentifier:
if IsDeclaration(parent) {
if parent.Name() == name {
return parent
}
return nil
}
if IsQualifiedName(parent) {
tag := parent.Parent
if IsJSDocParameterTag(tag) && tag.Name() == parent {
return tag
}
return nil
}
binExp := parent.Parent
if IsBinaryExpression(binExp) && GetAssignmentDeclarationKind(binExp) != JSDeclarationKindNone {
// (binExp.left as BindableStaticNameExpression).symbol || binExp.symbol
leftHasSymbol := false
if binExp.AsBinaryExpression().Left != nil && binExp.AsBinaryExpression().Left.Symbol() != nil {
leftHasSymbol = true
}
if leftHasSymbol || binExp.Symbol() != nil {
if GetNameOfDeclaration(binExp.AsNode()) == name {
return binExp.AsNode()
}
}
}
case KindPrivateIdentifier:
if IsDeclaration(parent) && parent.Name() == name {
return parent
}
}
return nil
}
func declarationIsWriteAccess(decl *Node) bool {
if decl == nil {
return false
}
// Consider anything in an ambient declaration to be a write access since it may be coming from JS.
if decl.Flags&NodeFlagsAmbient != 0 {
return true
}
switch decl.Kind {
case KindBinaryExpression,
KindBindingElement,
KindClassDeclaration,
KindClassExpression,
KindDefaultKeyword,
KindEnumDeclaration,
KindEnumMember,
KindExportSpecifier,
KindImportClause, // default import
KindImportEqualsDeclaration,
KindImportSpecifier,
KindInterfaceDeclaration,
KindJSDocCallbackTag,
KindJSDocTypedefTag,
KindJsxAttribute,
KindModuleDeclaration,
KindNamespaceExportDeclaration,
KindNamespaceImport,
KindNamespaceExport,
KindParameter,
KindShorthandPropertyAssignment,
KindTypeAliasDeclaration,
KindJSTypeAliasDeclaration,
KindTypeParameter:
return true
case KindPropertyAssignment:
// In `({ x: y } = 0);`, `x` is not a write access.
return !IsArrayLiteralOrObjectLiteralDestructuringPattern(decl.Parent)
case KindFunctionDeclaration, KindFunctionExpression, KindConstructor, KindMethodDeclaration, KindGetAccessor, KindSetAccessor:
// functions considered write if they provide a value (have a body)
switch decl.Kind {
case KindFunctionDeclaration:
return decl.AsFunctionDeclaration().Body != nil
case KindFunctionExpression:
return decl.AsFunctionExpression().Body != nil
case KindConstructor:
// constructor node stores body on the parent? treat same as others
return decl.AsConstructorDeclaration().Body != nil
case KindMethodDeclaration:
return decl.AsMethodDeclaration().Body != nil
case KindGetAccessor:
return decl.AsGetAccessorDeclaration().Body != nil
case KindSetAccessor:
return decl.AsSetAccessorDeclaration().Body != nil
}
return false
case KindVariableDeclaration, KindPropertyDeclaration:
// variable/property write if initializer present or is in catch clause
var hasInit bool
switch decl.Kind {
case KindVariableDeclaration:
hasInit = decl.AsVariableDeclaration().Initializer != nil
case KindPropertyDeclaration:
hasInit = decl.AsPropertyDeclaration().Initializer != nil
}
return hasInit || IsCatchClause(decl.Parent)
case KindMethodSignature, KindPropertySignature, KindJSDocPropertyTag, KindJSDocParameterTag:
return false
default:
// preserve TS behavior: crash on unexpected kinds
panic("Unhandled case in declarationIsWriteAccess")
}
}
func IsArrayLiteralOrObjectLiteralDestructuringPattern(node *Node) bool {
if !(IsArrayLiteralExpression(node) || IsObjectLiteralExpression(node)) {
return false
}
parent := node.Parent
// [a,b,c] from:
// [a, b, c] = someExpression;
if IsBinaryExpression(parent) && parent.AsBinaryExpression().Left == node && parent.AsBinaryExpression().OperatorToken.Kind == KindEqualsToken {
return true
}
// [a, b, c] from:
// for([a, b, c] of expression)
if IsForOfStatement(parent) && parent.Initializer() == node {
return true
}
// {x, a: {a, b, c} } = someExpression
if IsPropertyAssignment(parent) {
return IsArrayLiteralOrObjectLiteralDestructuringPattern(parent.Parent)
}
// [a, b, c] of
// [x, [a, b, c] ] = someExpression
return IsArrayLiteralOrObjectLiteralDestructuringPattern(parent)
}
func accessKind(node *Node) AccessKind {
parent := node.Parent
if parent == nil {
return AccessKindRead
}
switch parent.Kind {
case KindParenthesizedExpression:
return accessKind(parent)
case KindPrefixUnaryExpression:
operator := parent.AsPrefixUnaryExpression().Operator
if operator == KindPlusPlusToken || operator == KindMinusMinusToken {
return AccessKindReadWrite
}
return AccessKindRead
case KindPostfixUnaryExpression:
operator := parent.AsPostfixUnaryExpression().Operator
if operator == KindPlusPlusToken || operator == KindMinusMinusToken {
return AccessKindReadWrite
}
return AccessKindRead
case KindBinaryExpression:
if parent.AsBinaryExpression().Left == node {
operator := parent.AsBinaryExpression().OperatorToken
if IsAssignmentOperator(operator.Kind) {
if operator.Kind == KindEqualsToken {
return AccessKindWrite
}
return AccessKindReadWrite
}
}
return AccessKindRead
case KindPropertyAccessExpression:
if parent.AsPropertyAccessExpression().Name() != node {
return AccessKindRead
}
return accessKind(parent)
case KindPropertyAssignment:
parentAccess := accessKind(parent.Parent)
// In `({ x: varname }) = { x: 1 }`, the left `x` is a read, the right `x` is a write.
if node == parent.AsPropertyAssignment().Name() {
return reverseAccessKind(parentAccess)
}
return parentAccess
case KindShorthandPropertyAssignment:
// Assume it's the local variable being accessed, since we don't check public properties for --noUnusedLocals.
if node == parent.AsShorthandPropertyAssignment().ObjectAssignmentInitializer {
return AccessKindRead
}
return accessKind(parent.Parent)
case KindArrayLiteralExpression:
return accessKind(parent)
case KindForInStatement, KindForOfStatement:
if node == parent.AsForInOrOfStatement().Initializer {
return AccessKindWrite
}
return AccessKindRead
default:
return AccessKindRead
}
}
func reverseAccessKind(a AccessKind) AccessKind {
switch a {
case AccessKindRead:
return AccessKindWrite
case AccessKindWrite:
return AccessKindRead
case AccessKindReadWrite:
return AccessKindReadWrite
}
panic("Unhandled case in reverseAccessKind")
}
type AccessKind int32
const (
AccessKindRead AccessKind = iota // Only reads from a variable
AccessKindWrite // Only writes to a variable without ever reading it. E.g.: `x=1;`.
AccessKindReadWrite // Reads from and writes to a variable. E.g.: `f(x++);`, `x/=1`.
)
// DeclarationBase
func (node *DeclarationBase) DeclarationData() *DeclarationBase { return node }
func IsDeclarationNode(node *Node) bool {
return node.DeclarationData() != nil
}
// ExportableBase
func (node *ExportableBase) ExportableData() *ExportableBase { return node }
// ModifiersBase
func (node *ModifiersBase) Modifiers() *ModifierList { return node.modifiers }
func (node *ModifiersBase) setModifiers(modifiers *ModifierList) { node.modifiers = modifiers }
// LocalsContainerBase
func (node *LocalsContainerBase) LocalsContainerData() *LocalsContainerBase { return node }
func IsLocalsContainer(node *Node) bool {
return node.LocalsContainerData() != nil
}
// FunctionLikeBase
func (node *FunctionLikeBase) LocalsContainerData() *LocalsContainerBase {
return &node.LocalsContainerBase
}
func (node *FunctionLikeBase) FunctionLikeData() *FunctionLikeBase { return node }
// BodyBase
func (node *BodyBase) BodyData() *BodyBase { return node }
// FunctionLikeWithBodyBase
func (node *FunctionLikeWithBodyBase) LocalsContainerData() *LocalsContainerBase {
return &node.LocalsContainerBase
}
func (node *FunctionLikeWithBodyBase) FunctionLikeData() *FunctionLikeBase {
return &node.FunctionLikeBase
}
func (node *FunctionLikeWithBodyBase) BodyData() *BodyBase { return &node.BodyBase }
// FlowNodeBase
func (node *FlowNodeBase) FlowNodeData() *FlowNodeBase { return node }
// if you provide nil for file, this code will walk to the root of the tree to find the file
func (node *Node) JSDoc(file *SourceFile) []*Node {
if node.Flags&NodeFlagsHasJSDoc == 0 {
return nil
}
if file == nil {
file = GetSourceFileOfNode(node)
if file == nil {
return nil
}
}
if file.hasLazyJSDoc {
return file.resolveJSDoc(node)
}
return file.jsdocCache[node]
}
// EagerJSDoc returns JSDoc nodes that have already been parsed and cached,
// without triggering lazy JSDoc parsing.
func (node *Node) EagerJSDoc(file *SourceFile) []*Node {
if node.Flags&NodeFlagsHasJSDoc == 0 {
return nil
}
if file == nil {
file = GetSourceFileOfNode(node)
if file == nil {
return nil
}
}
if file.hasLazyJSDoc {
file.jsdocMu.RLock()
jsdocs := file.jsdocCache[node]
file.jsdocMu.RUnlock()
return jsdocs
}
return file.jsdocCache[node]
}
// CompositeBase
func (node *CompositeBase) subtreeFactsWorker(self nodeData) SubtreeFacts {
// computeSubtreeFacts() is expected to be idempotent, so races will only impact time, not correctness.
facts := SubtreeFacts(node.facts.Load())
if facts&SubtreeFactsComputed == 0 {
facts |= self.computeSubtreeFacts() | SubtreeFactsComputed
node.facts.Store(uint32(facts))
}
return facts &^ SubtreeFactsComputed
}
func (node *CompositeBase) computeSubtreeFacts() SubtreeFacts {
// This method must be implemented by the concrete node type.
panic("not implemented")
}
// TypeSyntaxBase
func (node *TypeSyntaxBase) computeSubtreeFacts() SubtreeFacts { return SubtreeContainsTypeScript }
func (node *TypeSyntaxBase) propagateSubtreeFacts() SubtreeFacts { return SubtreeContainsTypeScript }
func (node *Token) computeSubtreeFacts() SubtreeFacts {
switch node.Kind {
case KindUsingKeyword:
return SubtreeContainsUsing
case KindPublicKeyword,
KindPrivateKeyword,
KindProtectedKeyword,
KindReadonlyKeyword,
KindAbstractKeyword,
KindDeclareKeyword,
KindConstKeyword,
KindAnyKeyword,
KindNumberKeyword,
KindBigIntKeyword,
KindNeverKeyword,
KindObjectKeyword,
KindInKeyword,
KindOutKeyword,
KindOverrideKeyword,
KindStringKeyword,
KindBooleanKeyword,
KindSymbolKeyword,
KindVoidKeyword,
KindUnknownKeyword,
KindUndefinedKeyword,
KindExportKeyword:
return SubtreeContainsTypeScript
case KindAccessorKeyword:
return SubtreeContainsClassFields
case KindAsyncKeyword:
return SubtreeContainsAnyAwait
case KindSuperKeyword:
return SubtreeContainsLexicalSuper
case KindThisKeyword:
return SubtreeContainsLexicalThis
case KindAsteriskAsteriskToken, KindAsteriskAsteriskEqualsToken:
return SubtreeContainsExponentiationOperator
case KindQuestionQuestionToken:
return SubtreeContainsNullishCoalescing
case KindQuestionDotToken:
return SubtreeContainsOptionalChaining
case KindQuestionQuestionEqualsToken, KindBarBarEqualsToken, KindAmpersandAmpersandEqualsToken:
return SubtreeContainsLogicalAssignments
}
return SubtreeFactsNone
}
func (node *PrivateIdentifier) computeSubtreeFacts() SubtreeFacts {
return SubtreeContainsClassFields
}
func (f *NodeFactory) NewModifier(kind Kind) *Node {
return f.NewToken(kind)
}
func (node *Decorator) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) |
SubtreeContainsTypeScript |
SubtreeContainsDecorators
}
func (node *ForInOrOfStatement) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Initializer) |
propagateSubtreeFacts(node.Expression) |
propagateSubtreeFacts(node.Statement) |
core.IfElse(node.AwaitModifier != nil, SubtreeContainsForAwaitOrAsyncGenerator, SubtreeFactsNone)
}
func (node *ReturnStatement) computeSubtreeFacts() SubtreeFacts {
// return in an ES2018 async generator must be awaited
return propagateSubtreeFacts(node.Expression) | SubtreeContainsForAwaitOrAsyncGenerator
}
func (node *CatchClause) computeSubtreeFacts() SubtreeFacts {
res := propagateSubtreeFacts(node.VariableDeclaration) |
propagateSubtreeFacts(node.Block)
if node.VariableDeclaration == nil {
res |= SubtreeContainsMissingCatchClauseVariable
}
return res
}
func (node *CatchClause) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsCatchClause
}
func (node *VariableStatement) computeSubtreeFacts() SubtreeFacts {
if node.modifiers != nil && node.modifiers.ModifierFlags&ModifierFlagsAmbient != 0 {
return SubtreeContainsTypeScript
} else {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.DeclarationList)
}
}
func (node *VariableDeclaration) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.name) |
propagateEraseableSyntaxSubtreeFacts(node.ExclamationToken) |
propagateEraseableSyntaxSubtreeFacts(node.Type) |
propagateSubtreeFacts(node.Initializer)
}
func (node *VariableDeclarationList) computeSubtreeFacts() SubtreeFacts {
return propagateNodeListSubtreeFacts(node.Declarations, propagateSubtreeFacts) |
core.IfElse(node.Flags&NodeFlagsUsing != 0, SubtreeContainsUsing, SubtreeFactsNone)
}
func (node *VariableDeclarationList) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsVariableDeclarationList
}
func (node *BindingPattern) computeSubtreeFacts() SubtreeFacts {
switch node.Kind {
case KindObjectBindingPattern:
return propagateNodeListSubtreeFacts(node.Elements, propagateObjectBindingElementSubtreeFacts)
case KindArrayBindingPattern:
return propagateNodeListSubtreeFacts(node.Elements, propagateBindingElementSubtreeFacts)
default:
return SubtreeFactsNone
}
}
func (node *BindingPattern) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsBindingPattern
}
func (node *ParameterDeclaration) computeSubtreeFacts() SubtreeFacts {
if node.name != nil && IsThisIdentifier(node.name) {
return SubtreeContainsTypeScript
} else {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.name) |
propagateEraseableSyntaxSubtreeFacts(node.QuestionToken) |
propagateEraseableSyntaxSubtreeFacts(node.Type) |
propagateSubtreeFacts(node.Initializer)
}
}
func (node *ParameterDeclaration) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsParameter
}
func (node *BindingElement) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.PropertyName) |
propagateSubtreeFacts(node.name) |
propagateSubtreeFacts(node.Initializer) |
core.IfElse(node.DotDotDotToken != nil, SubtreeContainsRestOrSpread, SubtreeFactsNone)
}
func (node *FunctionDeclaration) computeSubtreeFacts() SubtreeFacts {
if node.Body == nil || node.ModifierFlags()&ModifierFlagsAmbient != 0 {
return SubtreeContainsTypeScript
} else {
isAsync := node.ModifierFlags()&ModifierFlagsAsync != 0
isGenerator := node.AsteriskToken != nil
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.AsteriskToken) |
propagateSubtreeFacts(node.name) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) |
propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) |
propagateEraseableSyntaxSubtreeFacts(node.Type) |
propagateEraseableSyntaxSubtreeFacts(node.FullSignature) |
propagateSubtreeFacts(node.Body) |
core.IfElse(isAsync && isGenerator, SubtreeContainsForAwaitOrAsyncGenerator, SubtreeFactsNone) |
core.IfElse(isAsync && !isGenerator, SubtreeContainsAnyAwait, SubtreeFactsNone)
}
}
func (node *FunctionDeclaration) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsFunction
}
// ClassLikeBase
func (node *ClassLikeBase) Name() *DeclarationName { return node.name }
func (node *ClassLikeBase) ClassLikeData() *ClassLikeBase { return node }
func (node *ClassLikeBase) computeSubtreeFacts() SubtreeFacts {
if node.modifiers != nil && node.modifiers.ModifierFlags&ModifierFlagsAmbient != 0 {
return SubtreeContainsTypeScript
} else {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.name) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) |
propagateNodeListSubtreeFacts(node.HeritageClauses, propagateSubtreeFacts) |
propagateNodeListSubtreeFacts(node.Members, propagateSubtreeFacts)
}
}
func (node *ClassDeclaration) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsClass
}
func (node *ClassExpression) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsClass
}
func (node *HeritageClause) computeSubtreeFacts() SubtreeFacts {
switch node.Token {
case KindExtendsKeyword:
return propagateNodeListSubtreeFacts(node.Types, propagateSubtreeFacts)
case KindImplementsKeyword:
return SubtreeContainsTypeScript
default:
return SubtreeFactsNone
}
}
func IsTypeOrJSTypeAliasDeclaration(node *Node) bool {
return node.Kind == KindTypeAliasDeclaration || node.Kind == KindJSTypeAliasDeclaration
}
func (node *EnumMember) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.name) |
propagateSubtreeFacts(node.Initializer) |
SubtreeContainsTypeScript
}
func (node *EnumDeclaration) computeSubtreeFacts() SubtreeFacts {
if node.modifiers != nil && node.modifiers.ModifierFlags&ModifierFlagsAmbient != 0 {
return SubtreeContainsTypeScript
} else {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.name) |
propagateNodeListSubtreeFacts(node.Members, propagateSubtreeFacts) |
SubtreeContainsTypeScript
}
}
func (node *ModuleDeclaration) computeSubtreeFacts() SubtreeFacts {
if node.ModifierFlags()&ModifierFlagsAmbient != 0 {
return SubtreeContainsTypeScript
} else {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.name) |
propagateSubtreeFacts(node.Body) |
SubtreeContainsTypeScript
}
}
func (node *ModuleDeclaration) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsModule
}
func (node *ImportEqualsDeclaration) computeSubtreeFacts() SubtreeFacts {
if node.IsTypeOnly || !IsExternalModuleReference(node.ModuleReference) {
return SubtreeContainsTypeScript
} else {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.name) |
propagateSubtreeFacts(node.ModuleReference)
}
}
func IsImportDeclarationOrJSImportDeclaration(node *Node) bool {
return node.Kind == KindImportDeclaration || node.Kind == KindJSImportDeclaration
}
func (node *ImportSpecifier) computeSubtreeFacts() SubtreeFacts {
if node.IsTypeOnly {
return SubtreeContainsTypeScript
} else {
return propagateSubtreeFacts(node.PropertyName) |
propagateSubtreeFacts(node.name)
}
}
func (node *ImportClause) computeSubtreeFacts() SubtreeFacts {
if node.PhaseModifier == KindTypeKeyword {
return SubtreeContainsTypeScript
} else {
return propagateSubtreeFacts(node.name) |
propagateSubtreeFacts(node.NamedBindings)
}
}
func (node *ExportAssignment) computeSubtreeFacts() SubtreeFacts {
return propagateModifierListSubtreeFacts(node.modifiers) | propagateSubtreeFacts(node.Type) | propagateSubtreeFacts(node.Expression) | core.IfElse(node.IsExportEquals, SubtreeContainsTypeScript, SubtreeFactsNone)
}
func IsAnyExportAssignment(node *Node) bool {
return node.Kind == KindExportAssignment
}
func (node *ExportDeclaration) computeSubtreeFacts() SubtreeFacts {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.ExportClause) |
propagateSubtreeFacts(node.ModuleSpecifier) |
propagateSubtreeFacts(node.Attributes) |
core.IfElse(node.IsTypeOnly, SubtreeContainsTypeScript, SubtreeFactsNone)
}
func (node *ExportSpecifier) computeSubtreeFacts() SubtreeFacts {
if node.IsTypeOnly {
return SubtreeContainsTypeScript
} else {
return propagateSubtreeFacts(node.PropertyName) |
propagateSubtreeFacts(node.name)
}
}
// NamedMemberBase
func (node *NamedMemberBase) DeclarationData() *DeclarationBase { return &node.DeclarationBase }
func (node *NamedMemberBase) Modifiers() *ModifierList { return node.modifiers }
func (node *NamedMemberBase) setModifiers(modifiers *ModifierList) { node.modifiers = modifiers }
func (node *NamedMemberBase) Name() *DeclarationName { return node.name }
func (node *ConstructorDeclaration) computeSubtreeFacts() SubtreeFacts {
if node.Body == nil {
return SubtreeContainsTypeScript
} else {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) |
propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) |
propagateEraseableSyntaxSubtreeFacts(node.Type) |
propagateEraseableSyntaxSubtreeFacts(node.FullSignature) |
propagateSubtreeFacts(node.Body)
}
}
func (node *ConstructorDeclaration) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsConstructor
}
func (node *AccessorDeclarationBase) IsAccessorDeclaration() {}
func (node *AccessorDeclarationBase) computeSubtreeFacts() SubtreeFacts {
if node.Body == nil {
return SubtreeContainsTypeScript
} else {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.name) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) |
propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) |
propagateEraseableSyntaxSubtreeFacts(node.Type) |
propagateEraseableSyntaxSubtreeFacts(node.FullSignature) |
propagateSubtreeFacts(node.Body)
}
}
func (node *AccessorDeclarationBase) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsAccessor |
propagateSubtreeFacts(node.name)
}
func (node *MethodDeclaration) computeSubtreeFacts() SubtreeFacts {
if node.Body == nil {
return SubtreeContainsTypeScript
} else {
isAsync := node.modifiers != nil && node.modifiers.ModifierFlags&ModifierFlagsAsync != 0
isGenerator := node.AsteriskToken != nil
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.AsteriskToken) |
propagateSubtreeFacts(node.name) |
propagateEraseableSyntaxSubtreeFacts(node.PostfixToken) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) |
propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) |
propagateSubtreeFacts(node.Body) |
propagateEraseableSyntaxSubtreeFacts(node.Type) |
propagateEraseableSyntaxSubtreeFacts(node.FullSignature) |
core.IfElse(isAsync && isGenerator, SubtreeContainsForAwaitOrAsyncGenerator, SubtreeFactsNone) |
core.IfElse(isAsync && !isGenerator, SubtreeContainsAnyAwait, SubtreeFactsNone)
}
}
func (node *MethodDeclaration) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsMethod |
propagateSubtreeFacts(node.name)
}
func (node *PropertyDeclaration) computeSubtreeFacts() SubtreeFacts {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.name) |
propagateEraseableSyntaxSubtreeFacts(node.PostfixToken) |
propagateEraseableSyntaxSubtreeFacts(node.Type) |
propagateSubtreeFacts(node.Initializer) |
SubtreeContainsClassFields
}
func (node *PropertyDeclaration) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsProperty |
propagateSubtreeFacts(node.name)
}
func (node *ClassStaticBlockDeclaration) computeSubtreeFacts() SubtreeFacts {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.Body) |
SubtreeContainsClassFields
}
func (node *KeywordExpression) computeSubtreeFacts() SubtreeFacts {
switch node.Kind {
case KindThisKeyword:
return SubtreeContainsLexicalThis
case KindSuperKeyword:
return SubtreeContainsLexicalSuper
}
return SubtreeFactsNone
}
// TemplateLiteralLikeBase
func (node *LiteralLikeNodeBase) LiteralLikeData() *LiteralLikeNodeBase { return node }
func (node *BigIntLiteral) computeSubtreeFacts() SubtreeFacts {
return SubtreeFactsNone // `bigint` is not downleveled in any way
}
func (node *Identifier) computeSubtreeFacts() SubtreeFacts {
return SubtreeContainsIdentifier
}
func (node *NoSubstitutionTemplateLiteral) computeSubtreeFacts() SubtreeFacts {
if node.TemplateFlags&TokenFlagsContainsInvalidEscape != 0 {
return SubtreeContainsInvalidTemplateEscape
}
return SubtreeFactsNone
}
func (node *BinaryExpression) computeSubtreeFacts() SubtreeFacts {
facts := propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.Left) |
propagateSubtreeFacts(node.Type) |
propagateSubtreeFacts(node.OperatorToken) |
propagateSubtreeFacts(node.Right) |
core.IfElse(node.OperatorToken.Kind == KindInKeyword && IsPrivateIdentifier(node.Left), SubtreeContainsClassFields|SubtreeContainsPrivateIdentifierInExpression, SubtreeFactsNone)
if node.OperatorToken.Kind == KindEqualsToken {
if (IsObjectLiteralExpression(node.Left) || IsArrayLiteralExpression(node.Left)) && ContainsObjectRestOrSpread(node.Left) {
facts |= SubtreeContainsObjectRestOrSpread
}
}
return facts
}
func (node *BinaryExpression) setModifiers(modifiers *ModifierList) { node.modifiers = modifiers }
func (node *YieldExpression) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) | SubtreeContainsForAwaitOrAsyncGenerator
}
func (node *ArrowFunction) computeSubtreeFacts() SubtreeFacts {
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) |
propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) |
propagateEraseableSyntaxSubtreeFacts(node.Type) |
propagateEraseableSyntaxSubtreeFacts(node.FullSignature) |
propagateSubtreeFacts(node.Body) |
core.IfElse(node.ModifierFlags()&ModifierFlagsAsync != 0, SubtreeContainsAnyAwait, SubtreeFactsNone)
}
func (node *ArrowFunction) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsArrowFunction
}
func (node *FunctionExpression) computeSubtreeFacts() SubtreeFacts {
isAsync := node.modifiers != nil && node.modifiers.ModifierFlags&ModifierFlagsAsync != 0
isGenerator := node.AsteriskToken != nil
return propagateModifierListSubtreeFacts(node.modifiers) |
propagateSubtreeFacts(node.AsteriskToken) |
propagateSubtreeFacts(node.name) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeParameters) |
propagateNodeListSubtreeFacts(node.Parameters, propagateSubtreeFacts) |
propagateEraseableSyntaxSubtreeFacts(node.Type) |
propagateEraseableSyntaxSubtreeFacts(node.FullSignature) |
propagateSubtreeFacts(node.Body) |
core.IfElse(isAsync && isGenerator, SubtreeContainsForAwaitOrAsyncGenerator, SubtreeFactsNone) |
core.IfElse(isAsync && !isGenerator, SubtreeContainsAnyAwait, SubtreeFactsNone)
}
func (node *FunctionExpression) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsFunction
}
func (node *AsExpression) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) | SubtreeContainsTypeScript
}
func (node *AsExpression) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsOuterExpression
}
func (node *SatisfiesExpression) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) | SubtreeContainsTypeScript
}
func (node *SatisfiesExpression) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsOuterExpression
}
func (node *PropertyAccessExpression) computeSubtreeFacts() SubtreeFacts {
privateName := SubtreeFactsNone
if !IsIdentifier(node.name) {
privateName = SubtreeContainsPrivateIdentifierInExpression
}
return propagateSubtreeFacts(node.Expression) |
propagateSubtreeFacts(node.QuestionDotToken) |
propagateSubtreeFacts(node.name) | privateName
}
func (node *PropertyAccessExpression) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsPropertyAccess
}
func (node *ElementAccessExpression) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsElementAccess
}
func (node *CallExpression) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) |
propagateSubtreeFacts(node.QuestionDotToken) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments) |
propagateNodeListSubtreeFacts(node.Arguments, propagateSubtreeFacts) |
core.IfElse(node.Expression.Kind == KindImportKeyword, SubtreeContainsDynamicImport, SubtreeFactsNone)
}
func (node *CallExpression) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsCall
}
func (node *NewExpression) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments) |
propagateNodeListSubtreeFacts(node.Arguments, propagateSubtreeFacts)
}
func (node *NewExpression) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsNew
}
func (node *MetaProperty) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.name) &^ SubtreeContainsIdentifier
}
func (node *NonNullExpression) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) | SubtreeContainsTypeScript
}
func (node *SpreadElement) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) | SubtreeContainsRestOrSpread
}
func (node *TaggedTemplateExpression) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Tag) |
propagateSubtreeFacts(node.QuestionDotToken) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments) |
propagateSubtreeFacts(node.Template)
}
// Hand-written subtree facts for nontrivial generated nodes.
func (node *ArrayLiteralExpression) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsArrayLiteral
}
func (node *ObjectLiteralExpression) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsObjectLiteral
}
func (node *SpreadAssignment) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) | SubtreeContainsESObjectRestOrSpread | SubtreeContainsObjectRestOrSpread
}
func (node *PropertyAssignment) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.name) |
propagateSubtreeFacts(node.Type) |
propagateSubtreeFacts(node.Initializer)
}
func (node *ShorthandPropertyAssignment) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.name) |
propagateSubtreeFacts(node.Type) |
propagateSubtreeFacts(node.ObjectAssignmentInitializer) |
SubtreeContainsTypeScript
}
func (node *AwaitExpression) computeSubtreeFacts() SubtreeFacts {
// await in an ES2018 async generator must use `yield __await(expr)`
return propagateSubtreeFacts(node.Expression) | SubtreeContainsAwait | SubtreeContainsAnyAwait | SubtreeContainsForAwaitOrAsyncGenerator
}
func (node *TypeAssertion) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) | SubtreeContainsTypeScript
}
func (node *TypeAssertion) propagateSubtreeFacts() SubtreeFacts {
return node.SubtreeFacts() & ^SubtreeExclusionsOuterExpression
}
func (node *ExpressionWithTypeArguments) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments)
}
func (node *ImportAttributesNode) GetResolutionModeOverride( /* !!! grammarErrorOnNode?: (node: Node, diagnostic: DiagnosticMessage) => void*/ ) (core.ResolutionMode, bool) {
if node == nil {
return core.ResolutionModeNone, false
}
attributes := node.AsImportAttributes().Attributes
if len(attributes.Nodes) != 1 {
// !!!
// grammarErrorOnNode?.(
// node,
// node.token === SyntaxKind.WithKeyword
// ? Diagnostics.Type_import_attributes_should_have_exactly_one_key_resolution_mode_with_value_import_or_require
// : Diagnostics.Type_import_assertions_should_have_exactly_one_key_resolution_mode_with_value_import_or_require,
// );
return core.ResolutionModeNone, false
}
elem := attributes.Nodes[0].AsImportAttribute()
if !IsStringLiteralLike(elem.Name()) {
return core.ResolutionModeNone, false
}
if elem.Name().Text() != "resolution-mode" {
// !!!
// grammarErrorOnNode?.(
// elem.name,
// node.token === SyntaxKind.WithKeyword
// ? Diagnostics.resolution_mode_is_the_only_valid_key_for_type_import_attributes
// : Diagnostics.resolution_mode_is_the_only_valid_key_for_type_import_assertions,
// );
return core.ResolutionModeNone, false
}
if !IsStringLiteralLike(elem.Value) {
return core.ResolutionModeNone, false
}
if elem.Value.Text() != "import" && elem.Value.Text() != "require" {
// !!!
// grammarErrorOnNode?.(elem.value, Diagnostics.resolution_mode_should_be_either_require_or_import);
return core.ResolutionModeNone, false
}
if elem.Value.Text() == "import" {
return core.ResolutionModeESM, true
} else {
return core.ModuleKindCommonJS, true
}
}
// FunctionOrConstructorTypeNodeBase
func (node *FunctionOrConstructorTypeNodeBase) DeclarationData() *DeclarationBase {
return node.FunctionLikeBase.DeclarationData()
}
func (node *TemplateLiteralLikeNodeBase) LiteralLikeData() *LiteralLikeNodeBase {
return &node.LiteralLikeNodeBase
}
func (node *TemplateLiteralLikeNodeBase) TemplateLiteralLikeData() *TemplateLiteralLikeNodeBase {
return node
}
func (node *TemplateHead) computeSubtreeFacts() SubtreeFacts {
if node.TemplateFlags&TokenFlagsContainsInvalidEscape != 0 {
return SubtreeContainsInvalidTemplateEscape
}
return SubtreeFactsNone
}
func (node *TemplateMiddle) computeSubtreeFacts() SubtreeFacts {
if node.TemplateFlags&TokenFlagsContainsInvalidEscape != 0 {
return SubtreeContainsInvalidTemplateEscape
}
return SubtreeFactsNone
}
func (node *TemplateTail) computeSubtreeFacts() SubtreeFacts {
if node.TemplateFlags&TokenFlagsContainsInvalidEscape != 0 {
return SubtreeContainsInvalidTemplateEscape
}
return SubtreeFactsNone
}
func (node *JsxElement) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.OpeningElement) |
propagateNodeListSubtreeFacts(node.Children, propagateSubtreeFacts) |
propagateSubtreeFacts(node.ClosingElement) |
SubtreeContainsJsx
}
func (node *JsxAttributes) computeSubtreeFacts() SubtreeFacts {
return propagateNodeListSubtreeFacts(node.Properties, propagateSubtreeFacts) |
SubtreeContainsJsx
}
func (node *JsxNamespacedName) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Namespace) |
propagateSubtreeFacts(node.name) |
SubtreeContainsJsx
}
func (node *JsxOpeningElement) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.TagName) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments) |
propagateSubtreeFacts(node.Attributes) |
SubtreeContainsJsx
}
func (node *JsxSelfClosingElement) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.TagName) |
propagateEraseableSyntaxListSubtreeFacts(node.TypeArguments) |
propagateSubtreeFacts(node.Attributes) |
SubtreeContainsJsx
}
func (node *JsxFragment) computeSubtreeFacts() SubtreeFacts {
return propagateNodeListSubtreeFacts(node.Children, propagateSubtreeFacts) |
SubtreeContainsJsx
}
func (node *JsxOpeningFragment) computeSubtreeFacts() SubtreeFacts {
return SubtreeContainsJsx
}
func (node *JsxClosingFragment) computeSubtreeFacts() SubtreeFacts {
return SubtreeContainsJsx
}
func (node *JsxAttribute) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.name) |
propagateSubtreeFacts(node.Initializer) |
SubtreeContainsJsx
}
func (node *JsxSpreadAttribute) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) | SubtreeContainsJsx
}
func (node *JsxClosingElement) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.TagName) | SubtreeContainsJsx
}
func (node *JsxExpression) computeSubtreeFacts() SubtreeFacts {
return propagateSubtreeFacts(node.Expression) | SubtreeContainsJsx
}
func (node *JsxText) computeSubtreeFacts() SubtreeFacts {
return SubtreeContainsJsx
}
/// JSDoc nodes ///
// JSDoc
func (node *Node) IsJSDoc() bool {
return node.Kind == KindJSDoc
}
// JSDocText
// PatternAmbientModule
type PatternAmbientModule struct {
Pattern core.Pattern
Symbol *Symbol
}
type CommentDirectiveKind int32
const (
CommentDirectiveKindUnknown CommentDirectiveKind = iota
CommentDirectiveKindExpectError
CommentDirectiveKindIgnore
)
type CommentDirective struct {
Loc core.TextRange
Kind CommentDirectiveKind
}
// SourceFile
type SourceFileMetaData struct {
PackageJsonType string
PackageJsonDirectory string
ImpliedNodeFormat core.ResolutionMode
}
// SourceFileDataKey identifies lazily-computed data attached to a SourceFile by
// another package. Prefer regular SourceFile fields for ast-owned data.
type SourceFileDataKey[T any] struct {
key sourceFileDataKey
_ [0]T
}
type sourceFileDataKey uint64
var sourceFileDataKeyCounter atomic.Uint64
type sourceFileDataCell[T any] struct {
once sync.Once
value T
}
func NewSourceFileDataKey[T any]() *SourceFileDataKey[T] {
return &SourceFileDataKey[T]{key: sourceFileDataKey(sourceFileDataKeyCounter.Add(1))}
}
func GetOrComputeSourceFileData[T any](file *SourceFile, key *SourceFileDataKey[T], compute func(*SourceFile) T) T {
cell := getSourceFileDataCell(file, key)
cell.once.Do(func() {
cell.value = compute(file)
})
return cell.value
}
func getSourceFileDataCell[T any](file *SourceFile, key *SourceFileDataKey[T]) *sourceFileDataCell[T] {
if key == nil || key.key == 0 {
panic("invalid SourceFileDataKey; use NewSourceFileDataKey")
}
file.dataMu.Lock()
defer file.dataMu.Unlock()
if file.data == nil {
file.data = make(map[sourceFileDataKey]any)
}
if cell, ok := file.data[key.key]; ok {
return cell.(*sourceFileDataCell[T])
}
cell := &sourceFileDataCell[T]{}
file.data[key.key] = cell
return cell
}
type CheckJsDirective struct {
Enabled bool
Range CommentRange
}
type HasFileName interface {
FileName() string
Path() tspath.Path
}
type TokenCacheKey struct {
parent *Node
loc core.TextRange
}
type SourceFile struct {
NodeBase
DeclarationBase
LocalsContainerBase
CompositeBase
// Fields set by NewSourceFile
fileName string // For debugging convenience
parseOptions SourceFileParseOptions
text string
Statements *NodeList // NodeList[*Statement]
EndOfFileToken *TokenNode // TokenNode[*EndOfFileToken]
// Fields for lazily-computed data owned by packages outside ast.
dataMu sync.Mutex
data map[sourceFileDataKey]any
// Fields set by parser
diagnostics []*Diagnostic
jsDiagnostics []*Diagnostic
jsdocDiagnostics []*Diagnostic
LanguageVariant core.LanguageVariant
ScriptKind core.ScriptKind
IsDeclarationFile bool
ContainsNonASCII bool
UsesUriStyleNodeCoreModules core.Tristate
Identifiers map[string]string
IdentifierCount int
imports []*LiteralLikeNode // []LiteralLikeNode
ModuleAugmentations []*ModuleName // []ModuleName
AmbientModuleNames []string
CommentDirectives []CommentDirective
jsdocCache map[*Node][]*Node
jsdocMu sync.RWMutex
hasLazyJSDoc bool
ReparsedClones []*Node
Pragmas []Pragma
ReferencedFiles []*FileReference
TypeReferenceDirectives []*FileReference
LibReferenceDirectives []*FileReference
CheckJsDirective *CheckJsDirective
NodeCount int
TextCount int
CommonJSModuleIndicator *Node
// If this is the SourceFile itself, then this module was "forced"
// to be an external module (previously "true").
ExternalModuleIndicator *Node
// Fields set by binder
isBound atomic.Bool
bindOnce sync.Once
bindDiagnostics []*Diagnostic
BindSuggestionDiagnostics []*Diagnostic
EndFlowNode *FlowNode
SymbolCount int
ClassifiableNames collections.Set[string]
PatternAmbientModules []*PatternAmbientModule
GlobalExports SymbolTable
// Fields set by ECMALineMap
ecmaLineMapMu sync.RWMutex
ecmaLineMap []core.TextPos
// Fields set by language service
Hash xxh3.Uint128
tokenCacheMu sync.Mutex
tokenCache map[TokenCacheKey]*Node
tokenFactory *NodeFactory
declarationMapMu sync.Mutex
declarationMap map[string][]*Node
nameTableOnce sync.Once
nameTable map[string]int
// Fields for UTF-8 to UTF-16 position mapping
positionMapOnce sync.Once
positionMap *PositionMap
}
func (f *NodeFactory) NewSourceFile(opts SourceFileParseOptions, text string, statements *NodeList, endOfFileToken *TokenNode) *Node {
if tspath.GetEncodedRootLength(opts.FileName) == 0 || opts.FileName != tspath.NormalizePath(opts.FileName) {
panic(fmt.Sprintf("fileName should be normalized and absolute: %q", opts.FileName))
}
data := &SourceFile{}
data.fileName = opts.FileName
data.parseOptions = opts
data.text = text
data.ContainsNonASCII = stringutil.ContainsNonASCII(text)
data.Statements = statements
data.EndOfFileToken = endOfFileToken
return f.newNode(KindSourceFile, data)
}
func (node *SourceFile) ParseOptions() SourceFileParseOptions {
return node.parseOptions
}
func (node *SourceFile) Text() string {
return node.text
}
func (node *SourceFile) FileName() string {
return node.parseOptions.FileName
}
func (node *SourceFile) Path() tspath.Path {
return node.parseOptions.Path
}
func (node *SourceFile) Imports() []*LiteralLikeNode {
return node.imports
}
func (node *SourceFile) Diagnostics() []*Diagnostic {
return node.diagnostics
}
func (node *SourceFile) SetDiagnostics(diags []*Diagnostic) {
node.diagnostics = diags
}
func (node *SourceFile) JSDiagnostics() []*Diagnostic {
return node.jsDiagnostics
}
func (node *SourceFile) SetJSDiagnostics(diags []*Diagnostic) {
node.jsDiagnostics = diags
}
func (node *SourceFile) JSDocDiagnostics() []*Diagnostic {
return node.jsdocDiagnostics
}
func (node *SourceFile) SetJSDocDiagnostics(diags []*Diagnostic) {
node.jsdocDiagnostics = diags
}
func (node *SourceFile) SetJSDocCache(cache map[*Node][]*Node) {
node.jsdocCache = cache
}
func (node *SourceFile) SetHasLazyJSDoc(lazy bool) {
node.hasLazyJSDoc = lazy
}
func (node *SourceFile) resolveJSDoc(n *Node) []*Node {
if parseJSDocForNode == nil {
panic("resolveJSDoc called but parseJSDocForNode is not registered; ensure the parser package is imported")
}
// Fast path: check cache under read lock
node.jsdocMu.RLock()
if jsdocs, ok := node.jsdocCache[n]; ok {
node.jsdocMu.RUnlock()
return jsdocs
}
node.jsdocMu.RUnlock()
// Slow path: parse and cache under write lock
node.jsdocMu.Lock()
defer node.jsdocMu.Unlock()
// Double-check after acquiring write lock
if jsdocs, ok := node.jsdocCache[n]; ok {
return jsdocs
}
jsdocs := parseJSDocForNode(node, n)
if node.jsdocCache == nil {
node.jsdocCache = make(map[*Node][]*Node)
}
node.jsdocCache[n] = jsdocs
return jsdocs
}
func (node *SourceFile) BindDiagnostics() []*Diagnostic {
return node.bindDiagnostics
}
func (node *SourceFile) SetBindDiagnostics(diags []*Diagnostic) {
node.bindDiagnostics = diags
}
func (node *SourceFile) ForEachChild(v Visitor) bool {
return visitNodeList(v, node.Statements) || visit(v, node.EndOfFileToken)
}
func (node *SourceFile) VisitEachChild(v *NodeVisitor) *Node {
return v.Factory.UpdateSourceFile(node, v.visitTopLevelStatements(node.Statements), v.visitToken(node.EndOfFileToken))
}
func (node *SourceFile) IsJS() bool {
return IsSourceFileJS(node)
}
func (node *SourceFile) copyFrom(other *SourceFile) {
// Do not copy fields set by NewSourceFile (Text, FileName, Path, or Statements)
node.LanguageVariant = other.LanguageVariant
node.ScriptKind = other.ScriptKind
node.IsDeclarationFile = other.IsDeclarationFile
node.ContainsNonASCII = other.ContainsNonASCII
node.UsesUriStyleNodeCoreModules = other.UsesUriStyleNodeCoreModules
node.Identifiers = other.Identifiers
node.imports = other.imports
node.ModuleAugmentations = other.ModuleAugmentations
node.AmbientModuleNames = other.AmbientModuleNames
node.CommentDirectives = other.CommentDirectives
node.Pragmas = other.Pragmas
node.ReferencedFiles = other.ReferencedFiles
node.TypeReferenceDirectives = other.TypeReferenceDirectives
node.LibReferenceDirectives = other.LibReferenceDirectives
node.CommonJSModuleIndicator = other.CommonJSModuleIndicator
node.ExternalModuleIndicator = other.ExternalModuleIndicator
node.Flags |= other.Flags
}
func (node *SourceFile) Clone(f NodeFactoryCoercible) *Node {
updated := f.AsNodeFactory().NewSourceFile(node.parseOptions, node.text, node.Statements, node.EndOfFileToken)
newFile := updated.AsSourceFile()
newFile.copyFrom(node)
return cloneNode(updated, node.AsNode(), f.AsNodeFactory().hooks)
}
func (node *SourceFile) computeSubtreeFacts() SubtreeFacts {
return propagateNodeListSubtreeFacts(node.Statements, propagateSubtreeFacts)
}
func (f *NodeFactory) UpdateSourceFile(node *SourceFile, statements *StatementList, endOfFileToken *TokenNode) *Node {
if statements != node.Statements || endOfFileToken != node.EndOfFileToken {
updated := f.NewSourceFile(node.parseOptions, node.text, statements, endOfFileToken).AsSourceFile()
updated.copyFrom(node)
return updateNode(updated.AsNode(), node.AsNode(), f.hooks)
}
return node.AsNode()
}
func (node *SourceFile) ECMALineMap() []core.TextPos {
node.ecmaLineMapMu.RLock()
lineMap := node.ecmaLineMap
node.ecmaLineMapMu.RUnlock()
if lineMap == nil {
node.ecmaLineMapMu.Lock()
defer node.ecmaLineMapMu.Unlock()
lineMap = node.ecmaLineMap
if lineMap == nil {
lineMap = core.ComputeECMALineStarts(node.Text())
node.ecmaLineMap = lineMap
}
}
return lineMap
}
// GetNameTable returns a map of all names in the file to their positions.
// If the name appears more than once, the value is -1.
func (file *SourceFile) GetNameTable() map[string]int {
file.nameTableOnce.Do(func() {
nameTable := make(map[string]int, file.IdentifierCount)
var walk func(node *Node) bool
walk = func(node *Node) bool {
if IsIdentifier(node) && !IsTagName(node) && node.Text() != "" ||
IsStringOrNumericLiteralLike(node) && literalIsName(node) ||
IsPrivateIdentifier(node) {
text := node.Text()
if _, ok := nameTable[text]; ok {
nameTable[text] = -1
} else {
nameTable[text] = node.Pos()
}
}
node.ForEachChild(walk)
jsdocNodes := node.JSDoc(file)
for _, jsdoc := range jsdocNodes {
jsdoc.ForEachChild(walk)
}
return false
}
file.ForEachChild(walk)
file.nameTable = nameTable
})
return file.nameTable
}
func (node *SourceFile) IsBound() bool {
return node.isBound.Load()
}
// GetPositionMap returns the PositionMap for this source file, computing it lazily.
func (file *SourceFile) GetPositionMap() *PositionMap {
file.positionMapOnce.Do(func() {
if !file.ContainsNonASCII {
file.positionMap = &PositionMap{asciiOnly: true}
} else {
file.positionMap = ComputePositionMap(file.Text())
}
})
return file.positionMap
}
func (node *SourceFile) BindOnce(bind func()) {
node.bindOnce.Do(func() {
bind()
node.isBound.Store(true)
})
}
// Gets a token from the file's token cache, or creates it if it does not already exist.
// This function should NOT be used for creating synthetic tokens that are not in the file in the first place.
func (node *SourceFile) GetOrCreateToken(
kind Kind,
pos int,
end int,
parent *Node,
flags TokenFlags,
) *TokenNode {
node.tokenCacheMu.Lock()
defer node.tokenCacheMu.Unlock()
loc := core.NewTextRange(pos, end)
key := TokenCacheKey{parent, loc}
if token, ok := node.tokenCache[key]; ok {
if token.Kind != kind {
panic(fmt.Sprintf("Token cache mismatch: %v != %v", token.Kind, kind))
}
return token
}
if parent.Flags&NodeFlagsReparsed != 0 {
panic(fmt.Sprintf("Cannot create token from reparsed node of kind %v", parent.Kind))
}
if node.tokenCache == nil {
node.tokenCache = make(map[TokenCacheKey]*Node)
}
token := createToken(kind, node, pos, end, flags)
token.Loc = loc
token.Parent = parent
node.tokenCache[key] = token
return token
}
// `kind` should be a token kind.
func createToken(kind Kind, file *SourceFile, pos, end int, flags TokenFlags) *Node {
if file.tokenFactory == nil {
file.tokenFactory = NewNodeFactory(NodeFactoryHooks{})
}
text := file.text[pos:end]
switch kind {
case KindNumericLiteral:
return file.tokenFactory.NewNumericLiteral(text, flags)
case KindBigIntLiteral:
return file.tokenFactory.NewBigIntLiteral(text, flags)
case KindStringLiteral:
return file.tokenFactory.NewStringLiteral(text, flags)
case KindJsxText, KindJsxTextAllWhiteSpaces:
return file.tokenFactory.NewJsxText(text, kind == KindJsxTextAllWhiteSpaces)
case KindRegularExpressionLiteral:
return file.tokenFactory.NewRegularExpressionLiteral(text, flags)
case KindNoSubstitutionTemplateLiteral:
return file.tokenFactory.NewNoSubstitutionTemplateLiteral(text, flags)
case KindTemplateHead:
return file.tokenFactory.NewTemplateHead(text, "" /*rawText*/, flags)
case KindTemplateMiddle:
return file.tokenFactory.NewTemplateMiddle(text, "" /*rawText*/, flags)
case KindTemplateTail:
return file.tokenFactory.NewTemplateTail(text, "" /*rawText*/, flags)
case KindIdentifier:
return file.tokenFactory.NewIdentifier(text)
case KindPrivateIdentifier:
return file.tokenFactory.NewPrivateIdentifier(text)
default: // Punctuation and keywords
return file.tokenFactory.NewToken(kind)
}
}
func (node *SourceFile) GetDeclarationMap() map[string][]*Node {
node.declarationMapMu.Lock()
defer node.declarationMapMu.Unlock()
if node.declarationMap == nil {
node.declarationMap = node.computeDeclarationMap()
}
return node.declarationMap
}
func (node *SourceFile) computeDeclarationMap() map[string][]*Node {
result := make(map[string][]*Node)
addDeclaration := func(declaration *Node) {
name := GetDeclarationName(declaration)
if name != "" {
result[name] = append(result[name], declaration)
}
}
var visit func(*Node) bool
visit = func(node *Node) bool {
switch node.Kind {
case KindFunctionDeclaration, KindFunctionExpression, KindMethodDeclaration, KindMethodSignature:
declarationName := GetDeclarationName(node)
if declarationName != "" {
declarations := result[declarationName]
var lastDeclaration *Node
if len(declarations) != 0 {
lastDeclaration = declarations[len(declarations)-1]
}
// Check whether this declaration belongs to an "overload group".
if lastDeclaration != nil && node.Parent == lastDeclaration.Parent && node.Symbol() == lastDeclaration.Symbol() {
// Overwrite the last declaration if it was an overload and this one is an implementation.
if node.Body() != nil && lastDeclaration.Body() == nil {
declarations[len(declarations)-1] = node
}
} else {
result[declarationName] = append(result[declarationName], node)
}
}
node.ForEachChild(visit)
case KindClassDeclaration, KindClassExpression, KindInterfaceDeclaration, KindTypeAliasDeclaration, KindEnumDeclaration, KindModuleDeclaration,
KindImportEqualsDeclaration, KindImportClause, KindNamespaceImport, KindGetAccessor, KindSetAccessor, KindTypeLiteral:
addDeclaration(node)
node.ForEachChild(visit)
case KindImportSpecifier, KindExportSpecifier:
if node.PropertyName() != nil {
addDeclaration(node)
}
case KindParameter:
// Only consider parameter properties
if !HasSyntacticModifier(node, ModifierFlagsParameterPropertyModifier) {
break
}
fallthrough
case KindVariableDeclaration, KindBindingElement:
name := node.Name()
if name != nil {
if IsBindingPattern(name) {
node.Name().ForEachChild(visit)
} else {
if node.Initializer() != nil {
visit(node.Initializer())
}
addDeclaration(node)
}
}
case KindEnumMember, KindPropertyDeclaration, KindPropertySignature:
addDeclaration(node)
case KindExportDeclaration:
// Handle named exports case e.g.:
// export {a, b as B} from "mod";
exportClause := node.AsExportDeclaration().ExportClause
if exportClause != nil {
if IsNamedExports(exportClause) {
for _, element := range exportClause.Elements() {
visit(element)
}
} else {
visit(exportClause.AsNamespaceExport().Name())
}
}
case KindImportDeclaration:
importClause := node.AsImportDeclaration().ImportClause
if importClause != nil {
// Handle default import case e.g.:
// import d from "mod";
if importClause.Name() != nil {
addDeclaration(importClause.Name())
}
// Handle named bindings in imports e.g.:
// import * as NS from "mod";
// import {a, b as B} from "mod";
namedBindings := importClause.AsImportClause().NamedBindings
if namedBindings != nil {
if namedBindings.Kind == KindNamespaceImport {
addDeclaration(namedBindings)
} else {
for _, element := range namedBindings.Elements() {
visit(element)
}
}
}
}
case KindBinaryExpression:
switch GetAssignmentDeclarationKind(node) {
case JSDeclarationKindExportsProperty, JSDeclarationKindThisProperty, JSDeclarationKindProperty:
addDeclaration(node)
}
node.ForEachChild(visit)
default:
node.ForEachChild(visit)
}
return false
}
node.ForEachChild(visit)
return result
}
func GetDeclarationName(declaration *Node) string {
name := GetNonAssignedNameOfDeclaration(declaration)
if name != nil {
if IsComputedPropertyName(name) {
if IsStringOrNumericLiteralLike(name.Expression()) {
return name.Expression().Text()
}
if IsPropertyAccessExpression(name.Expression()) {
return name.Expression().Name().Text()
}
} else if IsPropertyName(name) {
return name.Text()
}
}
return ""
}
type SourceFileLike interface {
Text() string
ECMALineMap() []core.TextPos
}
type CommentRange struct {
core.TextRange
Kind Kind
HasTrailingNewLine bool
}
func (f *NodeFactory) NewCommentRange(kind Kind, pos int, end int, hasTrailingNewLine bool) CommentRange {
return CommentRange{
TextRange: core.NewTextRange(pos, end),
Kind: kind,
HasTrailingNewLine: hasTrailingNewLine,
}
}
type FileReference struct {
core.TextRange
FileName string
ResolutionMode core.ResolutionMode
Preserve bool
}
type PragmaArgument struct {
core.TextRange
Name string
Value string
}
type Pragma struct {
CommentRange
Name string
Args map[string]PragmaArgument
}
type PragmaKindFlags = uint8
const (
PragmaKindTripleSlashXML PragmaKindFlags = 1 << iota
PragmaKindSingleLine
PragmaKindMultiLine
PragmaKindFlagsNone PragmaKindFlags = 0
PragmaKindAll = PragmaKindTripleSlashXML | PragmaKindSingleLine | PragmaKindMultiLine
PragmaKindDefault = PragmaKindAll
)
type PragmaArgumentSpecification struct {
Name string
Optional bool
CaptureSpan bool
}
type PragmaSpecification struct {
Args []PragmaArgumentSpecification
Kind PragmaKindFlags
}
func (spec *PragmaSpecification) IsTripleSlash() bool {
return (spec.Kind & PragmaKindTripleSlashXML) > 0
}
// Hand-written visitor implementations for nodes with runtime-dependent
// child ordering. Generated code in ast_generated.go delegates to these.
func forEachChild_JSDocParameterOrPropertyTag(node *JSDocParameterOrPropertyTag, v Visitor) bool {
return visit(v, node.TagName) ||
(node.IsNameFirst &&
(visit(v, node.name) || visit(v, node.TypeExpression))) ||
(!node.IsNameFirst &&
(visit(v, node.TypeExpression) || visit(v, node.name))) ||
visitNodeList(v, node.Comment)
}
func visitEachChild_JSDocParameterOrPropertyTag(node *JSDocParameterOrPropertyTag, v *NodeVisitor) *Node {
return v.Factory.UpdateJSDocParameterOrPropertyTag(node, v.visitNode(node.TagName), v.visitNode(node.name), node.IsBracketed, v.visitNode(node.TypeExpression), node.IsNameFirst, v.visitNodes(node.Comment))
}
func (f *NodeFactory) ReleaseArenas() {
*f = NodeFactory{
hooks: f.hooks,
textCount: f.textCount,
nodeCount: f.nodeCount,
}
}