Skip to content
  •  
  •  
  •  
14 changes: 12 additions & 2 deletions internal/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,12 @@ func (n *Node) TemplateLiteralLikeData() *TemplateLiteralLikeBase {
}
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

Expand Down Expand Up @@ -6300,7 +6306,7 @@ func (node *BinaryExpression) computeSubtreeFacts() SubtreeFacts {
propagateSubtreeFacts(node.Type) |
propagateSubtreeFacts(node.OperatorToken) |
propagateSubtreeFacts(node.Right) |
core.IfElse(node.OperatorToken.Kind == KindInKeyword && IsPrivateIdentifier(node.Left), SubtreeContainsClassFields, SubtreeFactsNone)
core.IfElse(node.OperatorToken.Kind == KindInKeyword && IsPrivateIdentifier(node.Left), SubtreeContainsClassFields|SubtreeContainsPrivateIdentifierInExpression, SubtreeFactsNone)
}

func (node *BinaryExpression) setModifiers(modifiers *ModifierList) { node.modifiers = modifiers }
Expand Down Expand Up @@ -6753,9 +6759,13 @@ func (node *PropertyAccessExpression) Clone(f NodeFactoryCoercible) *Node {
func (node *PropertyAccessExpression) Name() *DeclarationName { return node.name }

func (node *PropertyAccessExpression) computeSubtreeFacts() SubtreeFacts {
privateName := SubtreeFactsNone
if !IsIdentifier(node.name) {
privateName = SubtreeContainsPrivateIdentifierInExpression
}
return propagateSubtreeFacts(node.Expression) |
propagateSubtreeFacts(node.QuestionDotToken) |
propagateSubtreeFacts(node.name)
propagateSubtreeFacts(node.name) | privateName
}

func (node *PropertyAccessExpression) propagateSubtreeFacts() SubtreeFacts {
Expand Down
1 change: 1 addition & 0 deletions internal/ast/subtreefacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const (
SubtreeContainsClassFields
SubtreeContainsDecorators
SubtreeContainsIdentifier
SubtreeContainsPrivateIdentifierInExpression

SubtreeFactsComputed // NOTE: This should always be last
SubtreeFactsNone SubtreeFacts = 0
Expand Down
218 changes: 218 additions & 0 deletions internal/ast/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -3941,3 +3941,221 @@ func IsPotentiallyExecutableNode(node *Node) bool {
}
return IsClassDeclaration(node) || IsEnumDeclaration(node) || IsModuleDeclaration(node)
}

func HasAbstractModifier(node *Node) bool {
return HasSyntacticModifier(node, ModifierFlagsAbstract)
}

func HasAmbientModifier(node *Node) bool {
return HasSyntacticModifier(node, ModifierFlagsAmbient)
}

func NodeCanBeDecorated(useLegacyDecorators bool, node *Node, parent *Node, grandparent *Node) bool {
// private names cannot be used with decorators yet
if useLegacyDecorators && node.Name() != nil && IsPrivateIdentifier(node.Name()) {
return false
}
switch node.Kind {
case KindClassDeclaration:
// class declarations are valid targets
return true
case KindClassExpression:
// class expressions are valid targets for native decorators
return !useLegacyDecorators
case KindPropertyDeclaration:
// property declarations are valid if their parent is a class declaration.
return parent != nil && (useLegacyDecorators && IsClassDeclaration(parent) ||
!useLegacyDecorators && IsClassLike(parent) && !HasAbstractModifier(node) && !HasAmbientModifier(node))
case KindGetAccessor, KindSetAccessor, KindMethodDeclaration:
// if this method has a body and its parent is a class declaration, this is a valid target.
return parent != nil && node.Body() != nil && (useLegacyDecorators && IsClassDeclaration(parent) ||
!useLegacyDecorators && IsClassLike(parent))
case KindParameter:
// TODO(rbuckton): Parameter decorator support for ES decorators must wait until it is standardized
if !useLegacyDecorators {
return false
}
// if the parameter's parent has a body and its grandparent is a class declaration, this is a valid target.
return parent != nil && parent.Body() != nil &&
(parent.Kind == KindConstructor || parent.Kind == KindMethodDeclaration || parent.Kind == KindSetAccessor) &&
GetThisParameter(parent) != node && grandparent != nil && grandparent.Kind == KindClassDeclaration
}

return false
}

func ClassOrConstructorParameterIsDecorated(useLegacyDecorators bool, node *Node) bool {
if nodeIsDecorated(useLegacyDecorators, node, nil, nil) {
return true
}
constructor := GetFirstConstructorWithBody(node)
return constructor != nil && ChildIsDecorated(useLegacyDecorators, constructor, node)
}

func ClassElementOrClassElementParameterIsDecorated(useLegacyDecorators bool, node *Node, parent *Node) bool {
var parameters *NodeList
if IsAccessor(node) {
decls := GetAllAccessorDeclarations(parent.Members(), node)
var firstAccessorWithDecorators *Node
if HasDecorators(decls.FirstAccessor) {
firstAccessorWithDecorators = decls.FirstAccessor
} else if HasDecorators(decls.SecondAccessor) {
firstAccessorWithDecorators = decls.SecondAccessor
}
if firstAccessorWithDecorators == nil || node != firstAccessorWithDecorators {
return false
}
if decls.SetAccessor != nil {
parameters = decls.SetAccessor.Parameters
}
} else if IsMethodDeclaration(node) {
parameters = node.ParameterList()
}
if nodeIsDecorated(useLegacyDecorators, node, parent, nil) {
return true
}
if parameters != nil && len(parameters.Nodes) > 0 {
for _, parameter := range parameters.Nodes {
if IsThisParameter(parameter) {
continue
}
if nodeIsDecorated(useLegacyDecorators, parameter, node, parent) {
return true
}
}
}
return false
}

func nodeIsDecorated(useLegacyDecorators bool, node *Node, parent *Node, grandparent *Node) bool {
return HasDecorators(node) && NodeCanBeDecorated(useLegacyDecorators, node, parent, grandparent)
}

func NodeOrChildIsDecorated(useLegacyDecorators bool, node *Node, parent *Node, grandparent *Node) bool {
return nodeIsDecorated(useLegacyDecorators, node, parent, grandparent) || ChildIsDecorated(useLegacyDecorators, node, parent)
}

func ChildIsDecorated(useLegacyDecorators bool, node *Node, parent *Node) bool {
switch node.Kind {
case KindClassDeclaration, KindClassExpression:
return core.Some(node.Members(), func(m *Node) bool {
return NodeOrChildIsDecorated(useLegacyDecorators, m, node, parent)
})
case KindMethodDeclaration,
KindSetAccessor,
KindConstructor:
return core.Some(node.Parameters(), func(p *Node) bool {
return nodeIsDecorated(useLegacyDecorators, p, node, parent)
})
default:
return false
}
}

type AllAccessorDeclarations struct {
FirstAccessor *AccessorDeclaration
SecondAccessor *AccessorDeclaration
SetAccessor *SetAccessorDeclaration
GetAccessor *GetAccessorDeclaration
}

func GetAllAccessorDeclarationsForDeclaration(accessor *AccessorDeclaration, declarationsOfSymbol []*Node) AllAccessorDeclarations {
var otherKind Kind
if accessor.Kind == KindSetAccessor {
otherKind = KindGetAccessor
} else if accessor.Kind == KindGetAccessor {
otherKind = KindSetAccessor
} else {
panic(fmt.Sprintf("Unexpected node kind %q", accessor.Kind))
}
// otherAccessor := ast.GetDeclarationOfKind(c.getSymbolOfDeclaration(accessor), otherKind)
var otherAccessor *AccessorDeclaration
for _, d := range declarationsOfSymbol {
if d.Kind == otherKind {
otherAccessor = d
break
}
}

var firstAccessor *AccessorDeclaration
var secondAccessor *AccessorDeclaration
if otherAccessor != nil && (otherAccessor.Pos() < accessor.Pos()) {
firstAccessor = otherAccessor
secondAccessor = accessor
} else {
firstAccessor = accessor
secondAccessor = otherAccessor
}

var setAccessor *SetAccessorDeclaration
var getAccessor *GetAccessorDeclaration
if accessor.Kind == KindSetAccessor {
setAccessor = accessor.AsSetAccessorDeclaration()
if otherAccessor != nil {
getAccessor = otherAccessor.AsGetAccessorDeclaration()
}
} else {
getAccessor = accessor.AsGetAccessorDeclaration()
if otherAccessor != nil {
setAccessor = otherAccessor.AsSetAccessorDeclaration()
}
}

return AllAccessorDeclarations{
FirstAccessor: firstAccessor,
SecondAccessor: secondAccessor,
SetAccessor: setAccessor,
GetAccessor: getAccessor,
}
}

func GetAllAccessorDeclarations(parentDeclarations []*Node, accessor *AccessorDeclaration) AllAccessorDeclarations {
if HasDynamicName(accessor) {
// dynamic names can only be match up via checker symbol lookup, just return an object with just this accessor
return GetAllAccessorDeclarationsForDeclaration(accessor, []*Node{accessor})
}

accessorName := GetPropertyNameForPropertyNameNode(accessor.Name())
accessorStatic := IsStatic(accessor)
var matches []*Node
for _, member := range parentDeclarations {
if !IsAccessor(member) || IsStatic(member) != accessorStatic {
continue
}
memberName := GetPropertyNameForPropertyNameNode(member.Name())
if memberName == accessorName {
matches = append(matches, member)
}
}
return GetAllAccessorDeclarationsForDeclaration(accessor, matches)
}

func IsAsyncFunction(node *Node) bool {
switch node.Kind {
case KindFunctionDeclaration, KindFunctionExpression, KindArrowFunction, KindMethodDeclaration:
data := node.BodyData()
return data.Body != nil && data.AsteriskToken == nil && HasSyntacticModifier(node, ModifierFlagsAsync)
}
return false
}

/**
* Gets the most likely element type for a TypeNode. This is not an exhaustive test
* as it assumes a rest argument can only be an array type (either T[], or Array<T>).
*
* @param node The type node.
*
* @internal
*/
func GetRestParameterElementType(node *ParameterDeclarationNode) *Node {
if node == nil {
return node
}
if node.Kind == KindArrayType {
return node.AsArrayTypeNode().ElementType
}
if node.Kind == KindTypeReference && node.AsTypeReferenceNode().TypeArguments != nil {
return core.FirstOrNil(node.AsTypeReferenceNode().TypeArguments.Nodes)
}
return nil
}
9 changes: 0 additions & 9 deletions internal/binder/binder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2648,15 +2648,6 @@ func getOptionalSymbolFlagForNode(node *ast.Node) ast.SymbolFlags {
return core.IfElse(postfixToken != nil && postfixToken.Kind == ast.KindQuestionToken, ast.SymbolFlagsOptional, ast.SymbolFlagsNone)
}

func isAsyncFunction(node *ast.Node) bool {
switch node.Kind {
case ast.KindFunctionDeclaration, ast.KindFunctionExpression, ast.KindArrowFunction, ast.KindMethodDeclaration:
data := node.BodyData()
return data.Body != nil && data.AsteriskToken == nil && ast.HasSyntacticModifier(node, ast.ModifierFlagsAsync)
}
return false
}

func isFunctionSymbol(symbol *ast.Symbol) bool {
d := symbol.ValueDeclaration
if d != nil {
Expand Down
Loading
Loading