package ast import ( "fmt" "slices" "strings" "sync" "sync/atomic" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/debug" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath" ) // Atomic ids var ( nextNodeId atomic.Uint64 nextSymbolId atomic.Uint64 ) func GetNodeId(node *Node) NodeId { id := node.id.Load() if id == 0 { // Worst case, we burn a few ids if we have to CAS. id = nextNodeId.Add(1) if !node.id.CompareAndSwap(0, id) { id = node.id.Load() } } return NodeId(id) } func GetSymbolId(symbol *Symbol) SymbolId { id := symbol.id.Load() if id == 0 { // Worst case, we burn a few ids if we have to CAS. id = nextSymbolId.Add(1) if !symbol.id.CompareAndSwap(0, id) { id = symbol.id.Load() } } return SymbolId(id) } func GetSymbolTable(data *SymbolTable) SymbolTable { if *data == nil { *data = make(SymbolTable) } return *data } func GetMembers(symbol *Symbol) SymbolTable { return GetSymbolTable(&symbol.Members) } func GetExports(symbol *Symbol) SymbolTable { return GetSymbolTable(&symbol.Exports) } func GetLocals(container *Node) SymbolTable { return GetSymbolTable(&container.LocalsContainerData().Locals) } // Determines if a node is missing (either `nil` or empty) func NodeIsMissing(node *Node) bool { return node == nil || node.Loc.Pos() == node.Loc.End() && node.Loc.Pos() >= 0 && node.Kind != KindEndOfFile } // Determines if a node is present func NodeIsPresent(node *Node) bool { return !NodeIsMissing(node) } // Determines if a node contains synthetic positions func NodeIsSynthesized(node *Node) bool { return PositionIsSynthesized(node.Loc.Pos()) || PositionIsSynthesized(node.Loc.End()) } func RangeIsSynthesized(loc core.TextRange) bool { return PositionIsSynthesized(loc.Pos()) || PositionIsSynthesized(loc.End()) } // Determines whether a position is synthetic func PositionIsSynthesized(pos int) bool { return pos < 0 } func FindLastVisibleNode(nodes []*Node) *Node { fromEnd := 1 for fromEnd <= len(nodes) && nodes[len(nodes)-fromEnd].Flags&NodeFlagsReparsed != 0 { fromEnd++ } if fromEnd <= len(nodes) { return nodes[len(nodes)-fromEnd] } return nil } func NodeKindIs(node *Node, kinds ...Kind) bool { return slices.Contains(kinds, node.Kind) } func IsModifierKind(token Kind) bool { switch token { case KindAbstractKeyword, KindAccessorKeyword, KindAsyncKeyword, KindConstKeyword, KindDeclareKeyword, KindDefaultKeyword, KindExportKeyword, KindInKeyword, KindPublicKeyword, KindPrivateKeyword, KindProtectedKeyword, KindReadonlyKeyword, KindStaticKeyword, KindOutKeyword, KindOverrideKeyword: return true } return false } func IsModifier(node *Node) bool { return IsModifierKind(node.Kind) } func IsModifierLike(node *Node) bool { return IsModifier(node) || IsDecorator(node) } func IsKeywordKind(token Kind) bool { return KindFirstKeyword <= token && token <= KindLastKeyword } func IsPunctuationKind(token Kind) bool { return KindFirstPunctuation <= token && token <= KindLastPunctuation } func IsAssignmentOperator(token Kind) bool { return token >= KindFirstAssignment && token <= KindLastAssignment } func IsAssignmentExpression(node *Node, excludeCompoundAssignment bool) bool { if node.Kind == KindBinaryExpression { expr := node.AsBinaryExpression() return (expr.OperatorToken.Kind == KindEqualsToken || !excludeCompoundAssignment && IsAssignmentOperator(expr.OperatorToken.Kind)) && IsLeftHandSideExpression(expr.Left) } return false } func GetRightMostAssignedExpression(node *Node) *Node { for IsAssignmentExpression(node, true /*excludeCompoundAssignment*/) { node = node.AsBinaryExpression().Right } return node } func IsDestructuringAssignment(node *Node) bool { if IsAssignmentExpression(node, true /*excludeCompoundAssignment*/) { kind := node.AsBinaryExpression().Left.Kind return kind == KindObjectLiteralExpression || kind == KindArrayLiteralExpression } return false } // A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property // assignment in an object literal that is an assignment target, or if it is parented by an array literal that is // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ a }] = xxx'. // (Note that `p` is not a target in the above examples, only `a`.) func IsAssignmentTarget(node *Node) bool { return GetAssignmentTarget(node) != nil } // Returns the BinaryExpression, PrefixUnaryExpression, PostfixUnaryExpression, or ForInOrOfStatement that references // the given node as an assignment target func GetAssignmentTarget(node *Node) *Node { for { parent := node.Parent switch parent.Kind { case KindBinaryExpression: if IsAssignmentOperator(parent.AsBinaryExpression().OperatorToken.Kind) && parent.AsBinaryExpression().Left == node { return parent } return nil case KindPrefixUnaryExpression: if parent.AsPrefixUnaryExpression().Operator == KindPlusPlusToken || parent.AsPrefixUnaryExpression().Operator == KindMinusMinusToken { return parent } return nil case KindPostfixUnaryExpression: if parent.AsPostfixUnaryExpression().Operator == KindPlusPlusToken || parent.AsPostfixUnaryExpression().Operator == KindMinusMinusToken { return parent } return nil case KindForInStatement, KindForOfStatement: if parent.AsForInOrOfStatement().Initializer == node { return parent } return nil case KindParenthesizedExpression, KindArrayLiteralExpression, KindSpreadElement, KindNonNullExpression: node = parent case KindSpreadAssignment: node = parent.Parent case KindShorthandPropertyAssignment: if parent.AsShorthandPropertyAssignment().Name() != node { return nil } node = parent.Parent case KindPropertyAssignment: if parent.AsPropertyAssignment().Name() == node { return nil } node = parent.Parent default: return nil } } } func IsLogicalBinaryOperator(token Kind) bool { return token == KindBarBarToken || token == KindAmpersandAmpersandToken } func IsLogicalOrCoalescingBinaryOperator(token Kind) bool { return IsLogicalBinaryOperator(token) || token == KindQuestionQuestionToken } func IsLogicalOrCoalescingBinaryExpression(expr *Node) bool { return IsBinaryExpression(expr) && IsLogicalOrCoalescingBinaryOperator(expr.AsBinaryExpression().OperatorToken.Kind) } func IsLogicalOrCoalescingAssignmentOperator(token Kind) bool { return token == KindBarBarEqualsToken || token == KindAmpersandAmpersandEqualsToken || token == KindQuestionQuestionEqualsToken } func IsLogicalOrCoalescingAssignmentExpression(expr *Node) bool { return IsBinaryExpression(expr) && IsLogicalOrCoalescingAssignmentOperator(expr.AsBinaryExpression().OperatorToken.Kind) } func IsLogicalExpression(node *Node) bool { for { if node.Kind == KindParenthesizedExpression { node = node.AsParenthesizedExpression().Expression } else if node.Kind == KindPrefixUnaryExpression && node.AsPrefixUnaryExpression().Operator == KindExclamationToken { node = node.AsPrefixUnaryExpression().Operand } else { return IsLogicalOrCoalescingBinaryExpression(node) } } } func IsTokenKind(token Kind) bool { return KindFirstToken <= token && token <= KindLastToken } func IsAccessor(node *Node) bool { return node.Kind == KindGetAccessor || node.Kind == KindSetAccessor } func IsPropertyNameLiteral(node *Node) bool { switch node.Kind { case KindIdentifier, KindStringLiteral, KindNoSubstitutionTemplateLiteral, KindNumericLiteral: return true } return false } func IsMemberName(node *Node) bool { return node.Kind == KindIdentifier || node.Kind == KindPrivateIdentifier } func IsEntityName(node *Node) bool { return node.Kind == KindIdentifier || node.Kind == KindQualifiedName } func IsPropertyName(node *Node) bool { switch node.Kind { case KindIdentifier, KindPrivateIdentifier, KindStringLiteral, KindNumericLiteral, KindComputedPropertyName: return true } return false } // Return true if the given identifier is classified as an IdentifierName by inspecting the parent of the node func IsIdentifierName(node *Node) bool { parent := node.Parent switch parent.Kind { case KindPropertyDeclaration, KindPropertySignature, KindMethodDeclaration, KindMethodSignature, KindGetAccessor, KindSetAccessor, KindEnumMember, KindPropertyAssignment, KindPropertyAccessExpression: return parent.Name() == node case KindQualifiedName: return parent.AsQualifiedName().Right == node case KindBindingElement: return parent.AsBindingElement().PropertyName == node case KindImportSpecifier: return parent.AsImportSpecifier().PropertyName == node case KindExportSpecifier, KindJsxAttribute, KindJsxSelfClosingElement, KindJsxOpeningElement, KindJsxClosingElement: return true } return false } func IsPushOrUnshiftIdentifier(node *Node) bool { text := node.Text() return text == "push" || text == "unshift" } func IsBooleanLiteral(node *Node) bool { return node.Kind == KindTrueKeyword || node.Kind == KindFalseKeyword } func IsLiteralKind(kind Kind) bool { return KindFirstLiteralToken <= kind && kind <= KindLastLiteralToken } func IsLiteralExpression(node *Node) bool { return IsLiteralKind(node.Kind) } func IsStringLiteralLike(node *Node) bool { switch node.Kind { case KindStringLiteral, KindNoSubstitutionTemplateLiteral: return true } return false } func IsStringOrNumericLiteralLike(node *Node) bool { return IsStringLiteralLike(node) || IsNumericLiteral(node) } func IsSignedNumericLiteral(node *Node) bool { if node.Kind == KindPrefixUnaryExpression { node := node.AsPrefixUnaryExpression() return (node.Operator == KindPlusToken || node.Operator == KindMinusToken) && IsNumericLiteral(node.Operand) } return false } // Determines if a node is part of an OptionalChain func IsOptionalChain(node *Node) bool { if node.Flags&NodeFlagsOptionalChain != 0 { switch node.Kind { case KindPropertyAccessExpression, KindElementAccessExpression, KindCallExpression, KindNonNullExpression: return true } } return false } func getQuestionDotToken(node *Expression) *TokenNode { switch node.Kind { case KindPropertyAccessExpression: return node.AsPropertyAccessExpression().QuestionDotToken case KindElementAccessExpression: return node.AsElementAccessExpression().QuestionDotToken case KindCallExpression: return node.AsCallExpression().QuestionDotToken } panic("Unhandled case in getQuestionDotToken") } // Determines if node is the root expression of an OptionalChain func IsOptionalChainRoot(node *Expression) bool { return IsOptionalChain(node) && !IsNonNullExpression(node) && getQuestionDotToken(node) != nil } // Determines whether a node is the outermost `OptionalChain` in an ECMAScript `OptionalExpression`: // // 1. For `a?.b.c`, the outermost chain is `a?.b.c` (`c` is the end of the chain starting at `a?.`) // 2. For `a?.b!`, the outermost chain is `a?.b` (`b` is the end of the chain starting at `a?.`) // 3. For `(a?.b.c).d`, the outermost chain is `a?.b.c` (`c` is the end of the chain starting at `a?.` since parens end the chain) // 4. For `a?.b.c?.d`, both `a?.b.c` and `a?.b.c?.d` are outermost (`c` is the end of the chain starting at `a?.`, and `d` is // the end of the chain starting at `c?.`) // 5. For `a?.(b?.c).d`, both `b?.c` and `a?.(b?.c)d` are outermost (`c` is the end of the chain starting at `b`, and `d` is // the end of the chain starting at `a?.`) func IsOutermostOptionalChain(node *Expression) bool { parent := node.Parent return !IsOptionalChain(parent) || // cases 1, 2, and 3 IsOptionalChainRoot(parent) || // case 4 node != parent.Expression() // case 5 } // Determines whether a node is the expression preceding an optional chain (i.e. `a` in `a?.b`). func IsExpressionOfOptionalChainRoot(node *Node) bool { return IsOptionalChainRoot(node.Parent) && node.Parent.Expression() == node } func IsNullishCoalesce(node *Node) bool { return node.Kind == KindBinaryExpression && node.AsBinaryExpression().OperatorToken.Kind == KindQuestionQuestionToken } func IsAssertionExpression(node *Node) bool { kind := node.Kind return kind == KindTypeAssertionExpression || kind == KindAsExpression } func isLeftHandSideExpressionKind(kind Kind) bool { switch kind { case KindPropertyAccessExpression, KindElementAccessExpression, KindNewExpression, KindCallExpression, KindJsxElement, KindJsxSelfClosingElement, KindJsxFragment, KindTaggedTemplateExpression, KindArrayLiteralExpression, KindParenthesizedExpression, KindObjectLiteralExpression, KindClassExpression, KindFunctionExpression, KindIdentifier, KindPrivateIdentifier, KindRegularExpressionLiteral, KindNumericLiteral, KindBigIntLiteral, KindStringLiteral, KindNoSubstitutionTemplateLiteral, KindTemplateExpression, KindFalseKeyword, KindNullKeyword, KindThisKeyword, KindTrueKeyword, KindSuperKeyword, KindNonNullExpression, KindExpressionWithTypeArguments, KindMetaProperty, KindImportKeyword, KindMissingDeclaration: return true } return false } // Determines whether a node is a LeftHandSideExpression based only on its kind. func IsLeftHandSideExpression(node *Node) bool { return isLeftHandSideExpressionKind(node.Kind) } func isUnaryExpressionKind(kind Kind) bool { switch kind { case KindPrefixUnaryExpression, KindPostfixUnaryExpression, KindDeleteExpression, KindTypeOfExpression, KindVoidExpression, KindAwaitExpression, KindTypeAssertionExpression: return true } return isLeftHandSideExpressionKind(kind) } // Determines whether a node is a UnaryExpression based only on its kind. func IsUnaryExpression(node *Node) bool { return isUnaryExpressionKind(node.Kind) } func isExpressionKind(kind Kind) bool { switch kind { case KindConditionalExpression, KindYieldExpression, KindArrowFunction, KindBinaryExpression, KindSpreadElement, KindAsExpression, KindOmittedExpression, KindCommaListExpression, KindPartiallyEmittedExpression, KindSatisfiesExpression: return true } return isUnaryExpressionKind(kind) } // Determines whether a node is an expression based only on its kind. func IsExpression(node *Node) bool { return isExpressionKind(node.Kind) } func IsCommaExpression(node *Node) bool { return node.Kind == KindBinaryExpression && node.AsBinaryExpression().OperatorToken.Kind == KindCommaToken } func IsCommaSequence(node *Node) bool { // !!! // New compiler just has binary expressinons. // Maybe this should consider KindCommaListExpression even though we don't generate them. return IsCommaExpression(node) } func IsIterationStatement(node *Node, lookInLabeledStatements bool) bool { switch node.Kind { case KindForStatement, KindForInStatement, KindForOfStatement, KindDoStatement, KindWhileStatement: return true case KindLabeledStatement: return lookInLabeledStatements && IsIterationStatement((node.AsLabeledStatement()).Statement, lookInLabeledStatements) } return false } // Determines if a node is a property or element access expression func IsAccessExpression(node *Node) bool { return node.Kind == KindPropertyAccessExpression || node.Kind == KindElementAccessExpression } func isFunctionLikeDeclarationKind(kind Kind) bool { switch kind { case KindFunctionDeclaration, KindMethodDeclaration, KindConstructor, KindGetAccessor, KindSetAccessor, KindFunctionExpression, KindArrowFunction: return true } return false } // Determines if a node is function-like (but is not a signature declaration) func IsFunctionLikeDeclaration(node *Node) bool { // TODO(rbuckton): Move `node != nil` test to call sites return node != nil && isFunctionLikeDeclarationKind(node.Kind) } func IsFunctionLikeKind(kind Kind) bool { switch kind { case KindMethodSignature, KindCallSignature, KindJSDocSignature, KindConstructSignature, KindIndexSignature, KindFunctionType, KindConstructorType: return true } return isFunctionLikeDeclarationKind(kind) } // Determines if a node is function- or signature-like. func IsFunctionLike(node *Node) bool { // TODO(rbuckton): Move `node != nil` test to call sites return node != nil && IsFunctionLikeKind(node.Kind) } func IsFunctionLikeOrClassStaticBlockDeclaration(node *Node) bool { return node != nil && (IsFunctionLike(node) || IsClassStaticBlockDeclaration(node)) } func IsFunctionOrSourceFile(node *Node) bool { return IsFunctionLike(node) || IsSourceFile(node) } func IsClassLike(node *Node) bool { return node.Kind == KindClassDeclaration || node.Kind == KindClassExpression } func IsClassOrInterfaceLike(node *Node) bool { return node.Kind == KindClassDeclaration || node.Kind == KindClassExpression || node.Kind == KindInterfaceDeclaration } func IsClassElement(node *Node) bool { switch node.Kind { case KindConstructor, KindPropertyDeclaration, KindMethodDeclaration, KindGetAccessor, KindSetAccessor, KindIndexSignature, KindClassStaticBlockDeclaration, KindSemicolonClassElement: return true } return false } func isMethodOrAccessor(node *Node) bool { switch node.Kind { case KindMethodDeclaration, KindGetAccessor, KindSetAccessor: return true } return false } func IsPrivateIdentifierClassElementDeclaration(node *Node) bool { return (IsPropertyDeclaration(node) || isMethodOrAccessor(node)) && IsPrivateIdentifier(node.Name()) } func IsObjectLiteralOrClassExpressionMethodOrAccessor(node *Node) bool { kind := node.Kind return (kind == KindMethodDeclaration || kind == KindGetAccessor || kind == KindSetAccessor) && (node.Parent.Kind == KindObjectLiteralExpression || node.Parent.Kind == KindClassExpression) } func IsTypeElement(node *Node) bool { switch node.Kind { case KindConstructSignature, KindCallSignature, KindPropertySignature, KindMethodSignature, KindIndexSignature, KindGetAccessor, KindSetAccessor, KindNotEmittedTypeElement: return true } return false } func IsObjectLiteralElement(node *Node) bool { switch node.Kind { case KindPropertyAssignment, KindShorthandPropertyAssignment, KindSpreadAssignment, KindMethodDeclaration, KindGetAccessor, KindSetAccessor: return true } return false } func IsObjectLiteralMethod(node *Node) bool { return node != nil && node.Kind == KindMethodDeclaration && node.Parent.Kind == KindObjectLiteralExpression } func IsAutoAccessorPropertyDeclaration(node *Node) bool { return IsPropertyDeclaration(node) && HasAccessorModifier(node) } func IsParameterPropertyDeclaration(node *Node, parent *Node) bool { return IsParameter(node) && HasSyntacticModifier(node, ModifierFlagsParameterPropertyModifier) && parent.Kind == KindConstructor } func IsJsxChild(node *Node) bool { switch node.Kind { case KindJsxElement, KindJsxExpression, KindJsxSelfClosingElement, KindJsxText, KindJsxFragment: return true } return false } func IsJsxAttributeLike(node *Node) bool { return IsJsxAttribute(node) || IsJsxSpreadAttribute(node) } func isDeclarationStatementKind(kind Kind) bool { switch kind { case KindFunctionDeclaration, KindMissingDeclaration, KindClassDeclaration, KindInterfaceDeclaration, KindTypeAliasDeclaration, KindJSTypeAliasDeclaration, KindEnumDeclaration, KindModuleDeclaration, KindImportDeclaration, KindJSImportDeclaration, KindImportEqualsDeclaration, KindExportDeclaration, KindExportAssignment, KindJSExportAssignment, KindCommonJSExport, KindNamespaceExportDeclaration: return true } return false } // Determines whether a node is a DeclarationStatement. Ideally this does not use Parent pointers, but it may use them // to rule out a Block node that is part of `try` or `catch` or is the Block-like body of a function. // // NOTE: ECMA262 would just call this a Declaration func IsDeclarationStatement(node *Node) bool { return isDeclarationStatementKind(node.Kind) } func isStatementKindButNotDeclarationKind(kind Kind) bool { switch kind { case KindBreakStatement, KindContinueStatement, KindDebuggerStatement, KindDoStatement, KindExpressionStatement, KindEmptyStatement, KindForInStatement, KindForOfStatement, KindForStatement, KindIfStatement, KindLabeledStatement, KindReturnStatement, KindSwitchStatement, KindThrowStatement, KindTryStatement, KindVariableStatement, KindWhileStatement, KindWithStatement, KindNotEmittedStatement: return true } return false } // Determines whether a node is a Statement that is not also a Declaration. Ideally this does not use Parent pointers, // but it may use them to rule out a Block node that is part of `try` or `catch` or is the Block-like body of a function. // // NOTE: ECMA262 would just call this a Statement func IsStatementButNotDeclaration(node *Node) bool { return isStatementKindButNotDeclarationKind(node.Kind) } // Determines whether a node is a Statement. Ideally this does not use Parent pointers, but it may use // them to rule out a Block node that is part of `try` or `catch` or is the Block-like body of a function. // // NOTE: ECMA262 would call this either a StatementListItem or ModuleListItem func IsStatement(node *Node) bool { kind := node.Kind return isStatementKindButNotDeclarationKind(kind) || isDeclarationStatementKind(kind) || isBlockStatement(node) } // Determines whether a node is a BlockStatement. If parents are available, this ensures the Block is // not part of a `try` statement, `catch` clause, or the Block-like body of a function func isBlockStatement(node *Node) bool { if node.Kind != KindBlock { return false } if node.Parent != nil && (node.Parent.Kind == KindTryStatement || node.Parent.Kind == KindCatchClause) { return false } return !IsFunctionBlock(node) } // Determines whether a node is the Block-like body of a function by walking the parent of the node func IsFunctionBlock(node *Node) bool { return node != nil && node.Kind == KindBlock && node.Parent != nil && IsFunctionLike(node.Parent) } func GetStatementsOfBlock(block *Node) *StatementList { switch block.Kind { case KindBlock: return block.AsBlock().Statements case KindModuleBlock: return block.AsModuleBlock().Statements case KindSourceFile: return block.AsSourceFile().Statements } panic("Unhandled case in getStatementsOfBlock") } func IsBlockOrCatchScoped(declaration *Node) bool { return GetCombinedNodeFlags(declaration)&NodeFlagsBlockScoped != 0 || IsCatchClauseVariableDeclarationOrBindingElement(declaration) } func IsCatchClauseVariableDeclarationOrBindingElement(declaration *Node) bool { node := GetRootDeclaration(declaration) return node.Kind == KindVariableDeclaration && node.Parent.Kind == KindCatchClause } func IsTypeNodeKind(kind Kind) bool { switch kind { case KindAnyKeyword, KindUnknownKeyword, KindNumberKeyword, KindBigIntKeyword, KindObjectKeyword, KindBooleanKeyword, KindStringKeyword, KindSymbolKeyword, KindVoidKeyword, KindUndefinedKeyword, KindNeverKeyword, KindIntrinsicKeyword, KindExpressionWithTypeArguments, KindJSDocAllType, KindJSDocNullableType, KindJSDocNonNullableType, KindJSDocOptionalType, KindJSDocVariadicType: return true } return kind >= KindFirstTypeNode && kind <= KindLastTypeNode } func IsTypeNode(node *Node) bool { return IsTypeNodeKind(node.Kind) } func IsJSDocKind(kind Kind) bool { return KindFirstJSDocNode <= kind && kind <= KindLastJSDocNode } func isJSDocTypeAssertion(_ *Node) bool { return false // !!! } func IsPrologueDirective(node *Node) bool { return node.Kind == KindExpressionStatement && node.AsExpressionStatement().Expression.Kind == KindStringLiteral } type OuterExpressionKinds int16 const ( OEKParentheses OuterExpressionKinds = 1 << 0 OEKTypeAssertions OuterExpressionKinds = 1 << 1 OEKNonNullAssertions OuterExpressionKinds = 1 << 2 OEKPartiallyEmittedExpressions OuterExpressionKinds = 1 << 3 OEKExpressionsWithTypeArguments OuterExpressionKinds = 1 << 4 OEKSatisfies OuterExpressionKinds = 1 << 5 OEKExcludeJSDocTypeAssertion = 1 << 6 OEKAssertions = OEKTypeAssertions | OEKNonNullAssertions | OEKSatisfies OEKAll = OEKParentheses | OEKAssertions | OEKPartiallyEmittedExpressions | OEKExpressionsWithTypeArguments ) // Determines whether node is an "outer expression" of the provided kinds func IsOuterExpression(node *Expression, kinds OuterExpressionKinds) bool { switch node.Kind { case KindParenthesizedExpression: return kinds&OEKParentheses != 0 && !(kinds&OEKExcludeJSDocTypeAssertion != 0 && isJSDocTypeAssertion(node)) case KindTypeAssertionExpression, KindAsExpression: return kinds&OEKTypeAssertions != 0 case KindSatisfiesExpression: return kinds&(OEKExpressionsWithTypeArguments|OEKSatisfies) != 0 case KindExpressionWithTypeArguments: return kinds&OEKExpressionsWithTypeArguments != 0 case KindNonNullExpression: return kinds&OEKNonNullAssertions != 0 case KindPartiallyEmittedExpression: return kinds&OEKPartiallyEmittedExpressions != 0 } return false } // Descends into an expression, skipping past "outer expressions" of the provided kinds func SkipOuterExpressions(node *Expression, kinds OuterExpressionKinds) *Expression { for IsOuterExpression(node, kinds) { node = node.Expression() } return node } // Skips past the parentheses of an expression func SkipParentheses(node *Expression) *Expression { return SkipOuterExpressions(node, OEKParentheses) } func SkipTypeParentheses(node *Node) *Node { for IsParenthesizedTypeNode(node) { node = node.AsParenthesizedTypeNode().Type } return node } func SkipPartiallyEmittedExpressions(node *Expression) *Expression { return SkipOuterExpressions(node, OEKPartiallyEmittedExpressions) } // Walks up the parents of a parenthesized expression to find the containing node func WalkUpParenthesizedExpressions(node *Expression) *Node { for node != nil && node.Kind == KindParenthesizedExpression { node = node.Parent } return node } // Walks up the parents of a parenthesized type to find the containing node func WalkUpParenthesizedTypes(node *TypeNode) *Node { for node != nil && node.Kind == KindParenthesizedType { node = node.Parent } return node } // Walks up the parents of a node to find the containing SourceFile func GetSourceFileOfNode(node *Node) *SourceFile { for node != nil { if node.Kind == KindSourceFile { return node.AsSourceFile() } node = node.Parent } return nil } var setParentInChildrenPool = sync.Pool{ New: func() any { return newParentInChildrenSetter() }, } func newParentInChildrenSetter() func(node *Node) bool { // Consolidate state into one allocation. // Similar to https://go.dev/cl/552375. var state struct { parent *Node visit func(*Node) bool } state.visit = func(node *Node) bool { if state.parent != nil { node.Parent = state.parent } saveParent := state.parent state.parent = node node.ForEachChild(state.visit) state.parent = saveParent return false } return state.visit } func SetParentInChildren(node *Node) { fn := setParentInChildrenPool.Get().(func(node *Node) bool) defer setParentInChildrenPool.Put(fn) fn(node) } // This should never be called outside the parser func SetImportsOfSourceFile(node *SourceFile, imports []*LiteralLikeNode) { node.imports = imports } // Walks up the parents of a node to find the ancestor that matches the callback func FindAncestor(node *Node, callback func(*Node) bool) *Node { for node != nil { if callback(node) { return node } node = node.Parent } return nil } // Walks up the parents of a node to find the ancestor that matches the kind func FindAncestorKind(node *Node, kind Kind) *Node { for node != nil { if node.Kind == kind { return node } node = node.Parent } return nil } type FindAncestorResult int32 const ( FindAncestorFalse FindAncestorResult = iota FindAncestorTrue FindAncestorQuit ) func ToFindAncestorResult(b bool) FindAncestorResult { if b { return FindAncestorTrue } return FindAncestorFalse } // Walks up the parents of a node to find the ancestor that matches the callback func FindAncestorOrQuit(node *Node, callback func(*Node) FindAncestorResult) *Node { for node != nil { switch callback(node) { case FindAncestorQuit: return nil case FindAncestorTrue: return node } node = node.Parent } return nil } func IsNodeDescendantOf(node *Node, ancestor *Node) bool { for node != nil { if node == ancestor { return true } node = node.Parent } return false } func ModifierToFlag(token Kind) ModifierFlags { switch token { case KindStaticKeyword: return ModifierFlagsStatic case KindPublicKeyword: return ModifierFlagsPublic case KindProtectedKeyword: return ModifierFlagsProtected case KindPrivateKeyword: return ModifierFlagsPrivate case KindAbstractKeyword: return ModifierFlagsAbstract case KindAccessorKeyword: return ModifierFlagsAccessor case KindExportKeyword: return ModifierFlagsExport case KindDeclareKeyword: return ModifierFlagsAmbient case KindConstKeyword: return ModifierFlagsConst case KindDefaultKeyword: return ModifierFlagsDefault case KindAsyncKeyword: return ModifierFlagsAsync case KindReadonlyKeyword: return ModifierFlagsReadonly case KindOverrideKeyword: return ModifierFlagsOverride case KindInKeyword: return ModifierFlagsIn case KindOutKeyword: return ModifierFlagsOut case KindDecorator: return ModifierFlagsDecorator } return ModifierFlagsNone } func ModifiersToFlags(modifiers []*Node) ModifierFlags { var flags ModifierFlags for _, modifier := range modifiers { flags |= ModifierToFlag(modifier.Kind) } return flags } func HasSyntacticModifier(node *Node, flags ModifierFlags) bool { return node.ModifierFlags()&flags != 0 } func HasAccessorModifier(node *Node) bool { return HasSyntacticModifier(node, ModifierFlagsAccessor) } func HasStaticModifier(node *Node) bool { return HasSyntacticModifier(node, ModifierFlagsStatic) } func IsStatic(node *Node) bool { // https://tc39.es/ecma262/#sec-static-semantics-isstatic return IsClassElement(node) && HasStaticModifier(node) || IsClassStaticBlockDeclaration(node) } func CanHaveSymbol(node *Node) bool { switch node.Kind { case KindArrowFunction, KindBinaryExpression, KindBindingElement, KindCallExpression, KindCallSignature, KindClassDeclaration, KindClassExpression, KindClassStaticBlockDeclaration, KindConstructor, KindConstructorType, KindConstructSignature, KindElementAccessExpression, KindEnumDeclaration, KindEnumMember, KindExportAssignment, KindExportDeclaration, KindExportSpecifier, KindFunctionDeclaration, KindFunctionExpression, KindFunctionType, KindGetAccessor, KindImportClause, KindImportEqualsDeclaration, KindImportSpecifier, KindIndexSignature, KindInterfaceDeclaration, KindJSExportAssignment, KindJSTypeAliasDeclaration, KindCommonJSExport, KindJsxAttribute, KindJsxAttributes, KindJsxSpreadAttribute, KindMappedType, KindMethodDeclaration, KindMethodSignature, KindModuleDeclaration, KindNamedTupleMember, KindNamespaceExport, KindNamespaceExportDeclaration, KindNamespaceImport, KindNewExpression, KindNoSubstitutionTemplateLiteral, KindNumericLiteral, KindObjectLiteralExpression, KindParameter, KindPropertyAccessExpression, KindPropertyAssignment, KindPropertyDeclaration, KindPropertySignature, KindSetAccessor, KindShorthandPropertyAssignment, KindSourceFile, KindSpreadAssignment, KindStringLiteral, KindTypeAliasDeclaration, KindTypeLiteral, KindTypeParameter, KindVariableDeclaration: return true } return false } func CanHaveIllegalDecorators(node *Node) bool { switch node.Kind { case KindPropertyAssignment, KindShorthandPropertyAssignment, KindFunctionDeclaration, KindConstructor, KindIndexSignature, KindClassStaticBlockDeclaration, KindMissingDeclaration, KindVariableStatement, KindInterfaceDeclaration, KindTypeAliasDeclaration, KindEnumDeclaration, KindModuleDeclaration, KindImportEqualsDeclaration, KindImportDeclaration, KindJSImportDeclaration, KindNamespaceExportDeclaration, KindExportDeclaration, KindExportAssignment: return true } return false } func CanHaveIllegalModifiers(node *Node) bool { switch node.Kind { case KindClassStaticBlockDeclaration, KindPropertyAssignment, KindShorthandPropertyAssignment, KindMissingDeclaration, KindNamespaceExportDeclaration: return true } return false } func CanHaveModifiers(node *Node) bool { switch node.Kind { case KindTypeParameter, KindParameter, KindPropertySignature, KindPropertyDeclaration, KindMethodSignature, KindMethodDeclaration, KindConstructor, KindGetAccessor, KindSetAccessor, KindIndexSignature, KindConstructorType, KindFunctionExpression, KindArrowFunction, KindClassExpression, KindVariableStatement, KindFunctionDeclaration, KindClassDeclaration, KindInterfaceDeclaration, KindTypeAliasDeclaration, KindEnumDeclaration, KindModuleDeclaration, KindImportEqualsDeclaration, KindImportDeclaration, KindJSImportDeclaration, KindExportAssignment, KindExportDeclaration: return true } return false } func CanHaveDecorators(node *Node) bool { switch node.Kind { case KindParameter, KindPropertyDeclaration, KindMethodDeclaration, KindGetAccessor, KindSetAccessor, KindClassExpression, KindClassDeclaration: return true } return false } func IsFunctionOrModuleBlock(node *Node) bool { return IsSourceFile(node) || IsModuleBlock(node) || IsBlock(node) && IsFunctionLike(node.Parent) } func IsFunctionExpressionOrArrowFunction(node *Node) bool { return IsFunctionExpression(node) || IsArrowFunction(node) } // Warning: This has the same semantics as the forEach family of functions in that traversal terminates // in the event that 'visitor' returns true. func ForEachReturnStatement(body *Node, visitor func(stmt *Node) bool) bool { var traverse func(*Node) bool traverse = func(node *Node) bool { switch node.Kind { case KindReturnStatement: return visitor(node) case KindCaseBlock, KindBlock, KindIfStatement, KindDoStatement, KindWhileStatement, KindForStatement, KindForInStatement, KindForOfStatement, KindWithStatement, KindSwitchStatement, KindCaseClause, KindDefaultClause, KindLabeledStatement, KindTryStatement, KindCatchClause: return node.ForEachChild(traverse) } return false } return traverse(body) } func GetRootDeclaration(node *Node) *Node { for node.Kind == KindBindingElement { node = node.Parent.Parent } return node } func getCombinedFlags[T ~uint32](node *Node, getFlags func(*Node) T) T { node = GetRootDeclaration(node) flags := getFlags(node) if node.Kind == KindVariableDeclaration { node = node.Parent } if node != nil && node.Kind == KindVariableDeclarationList { flags |= getFlags(node) node = node.Parent } if node != nil && node.Kind == KindVariableStatement { flags |= getFlags(node) } return flags } func GetCombinedModifierFlags(node *Node) ModifierFlags { return getCombinedFlags(node, (*Node).ModifierFlags) } func GetCombinedNodeFlags(node *Node) NodeFlags { return getCombinedFlags(node, getNodeFlags) } func getNodeFlags(node *Node) NodeFlags { return node.Flags } // Gets whether a bound `VariableDeclaration` or `VariableDeclarationList` is part of an `await using` declaration. func IsVarAwaitUsing(node *Node) bool { return GetCombinedNodeFlags(node)&NodeFlagsBlockScoped == NodeFlagsAwaitUsing } // Gets whether a bound `VariableDeclaration` or `VariableDeclarationList` is part of a `using` declaration. func IsVarUsing(node *Node) bool { return GetCombinedNodeFlags(node)&NodeFlagsBlockScoped == NodeFlagsUsing } // Gets whether a bound `VariableDeclaration` or `VariableDeclarationList` is part of a `const` declaration. func IsVarConst(node *Node) bool { return GetCombinedNodeFlags(node)&NodeFlagsBlockScoped == NodeFlagsConst } // Gets whether a bound `VariableDeclaration` or `VariableDeclarationList` is part of a `const`, `using` or `await using` declaration. func IsVarConstLike(node *Node) bool { switch GetCombinedNodeFlags(node) & NodeFlagsBlockScoped { case NodeFlagsConst, NodeFlagsUsing, NodeFlagsAwaitUsing: return true } return false } // Gets whether a bound `VariableDeclaration` or `VariableDeclarationList` is part of a `let` declaration. func IsVarLet(node *Node) bool { return GetCombinedNodeFlags(node)&NodeFlagsBlockScoped == NodeFlagsLet } func IsImportMeta(node *Node) bool { if node.Kind == KindMetaProperty { return node.AsMetaProperty().KeywordToken == KindImportKeyword && node.AsMetaProperty().Name().AsIdentifier().Text == "meta" } return false } func WalkUpBindingElementsAndPatterns(binding *Node) *Node { node := binding.Parent for IsBindingElement(node.Parent) { node = node.Parent.Parent } return node.Parent } func IsSourceFileJS(file *SourceFile) bool { return file.ScriptKind == core.ScriptKindJS || file.ScriptKind == core.ScriptKindJSX } func IsInJSFile(node *Node) bool { return node != nil && node.Flags&NodeFlagsJavaScriptFile != 0 } func IsDeclaration(node *Node) bool { if node.Kind == KindTypeParameter { return node.Parent != nil } return IsDeclarationNode(node) } // True if `name` is the name of a declaration node func IsDeclarationName(name *Node) bool { return !IsSourceFile(name) && !IsBindingPattern(name) && IsDeclaration(name.Parent) && name.Parent.Name() == name } // Like 'isDeclarationName', but returns true for LHS of `import { x as y }` or `export { x as y }`. func IsDeclarationNameOrImportPropertyName(name *Node) bool { switch name.Parent.Kind { case KindImportSpecifier, KindExportSpecifier: return IsIdentifier(name) || name.Kind == KindStringLiteral default: return IsDeclarationName(name) } } func IsLiteralComputedPropertyDeclarationName(node *Node) bool { return IsStringOrNumericLiteralLike(node) && node.Parent.Kind == KindComputedPropertyName && IsDeclaration(node.Parent.Parent) } func IsExternalModuleImportEqualsDeclaration(node *Node) bool { return node.Kind == KindImportEqualsDeclaration && node.AsImportEqualsDeclaration().ModuleReference.Kind == KindExternalModuleReference } func IsModuleOrEnumDeclaration(node *Node) bool { return node.Kind == KindModuleDeclaration || node.Kind == KindEnumDeclaration } func IsLiteralImportTypeNode(node *Node) bool { return IsImportTypeNode(node) && IsLiteralTypeNode(node.AsImportTypeNode().Argument) && IsStringLiteral(node.AsImportTypeNode().Argument.AsLiteralTypeNode().Literal) } func IsJsxTagName(node *Node) bool { parent := node.Parent switch parent.Kind { case KindJsxOpeningElement, KindJsxClosingElement, KindJsxSelfClosingElement: return parent.TagName() == node } return false } func IsImportOrExportSpecifier(node *Node) bool { return IsImportSpecifier(node) || IsExportSpecifier(node) } func isVoidZero(node *Node) bool { return IsVoidExpression(node) && IsNumericLiteral(node.Expression()) && node.Expression().Text() == "0" } func IsVoidExpression(node *Node) bool { return node.Kind == KindVoidExpression } func IsExportsIdentifier(node *Node) bool { return IsIdentifier(node) && node.Text() == "exports" } func IsModuleIdentifier(node *Node) bool { return IsIdentifier(node) && node.Text() == "module" } func IsThisIdentifier(node *Node) bool { return IsIdentifier(node) && node.Text() == "this" } func IsThisParameter(node *Node) bool { return IsParameter(node) && node.Name() != nil && IsThisIdentifier(node.Name()) } func IsBindableStaticAccessExpression(node *Node, excludeThisKeyword bool) bool { return IsPropertyAccessExpression(node) && (!excludeThisKeyword && node.Expression().Kind == KindThisKeyword || IsIdentifier(node.Name()) && IsBindableStaticNameExpression(node.Expression() /*excludeThisKeyword*/, true)) || IsBindableStaticElementAccessExpression(node, excludeThisKeyword) } func IsBindableStaticElementAccessExpression(node *Node, excludeThisKeyword bool) bool { return IsLiteralLikeElementAccess(node) && ((!excludeThisKeyword && node.Expression().Kind == KindThisKeyword) || IsEntityNameExpression(node.Expression()) || IsBindableStaticAccessExpression(node.Expression(), true /*excludeThisKeyword*/)) } func IsLiteralLikeElementAccess(node *Node) bool { return IsElementAccessExpression(node) && IsStringOrNumericLiteralLike(node.AsElementAccessExpression().ArgumentExpression) } func IsBindableStaticNameExpression(node *Node, excludeThisKeyword bool) bool { return IsEntityNameExpression(node) || IsBindableStaticAccessExpression(node, excludeThisKeyword) } // Does not handle signed numeric names like `a[+0]` - handling those would require handling prefix unary expressions // throughout late binding handling as well, which is awkward (but ultimately probably doable if there is demand) func GetElementOrPropertyAccessName(node *Node) *Node { switch node.Kind { case KindPropertyAccessExpression: if IsIdentifier(node.Name()) { return node.Name() } return nil case KindElementAccessExpression: if arg := SkipParentheses(node.AsElementAccessExpression().ArgumentExpression); IsStringOrNumericLiteralLike(arg) { return arg } return nil } panic("Unhandled case in GetElementOrPropertyAccessName") } func GetInitializerOfBinaryExpression(expr *BinaryExpression) *Expression { for IsBinaryExpression(expr.Right) { expr = expr.Right.AsBinaryExpression() } return expr.Right.Expression() } func IsExpressionWithTypeArgumentsInClassExtendsClause(node *Node) bool { return TryGetClassExtendingExpressionWithTypeArguments(node) != nil } func TryGetClassExtendingExpressionWithTypeArguments(node *Node) *ClassLikeDeclaration { cls, isImplements := TryGetClassImplementingOrExtendingExpressionWithTypeArguments(node) if cls != nil && !isImplements { return cls } return nil } func TryGetClassImplementingOrExtendingExpressionWithTypeArguments(node *Node) (class *ClassLikeDeclaration, isImplements bool) { if IsExpressionWithTypeArguments(node) { if IsHeritageClause(node.Parent) && IsClassLike(node.Parent.Parent) { return node.Parent.Parent, node.Parent.AsHeritageClause().Token == KindImplementsKeyword } } return nil, false } func GetNameOfDeclaration(declaration *Node) *Node { if declaration == nil { return nil } nonAssignedName := GetNonAssignedNameOfDeclaration(declaration) if nonAssignedName != nil { return nonAssignedName } if IsFunctionExpression(declaration) || IsArrowFunction(declaration) || IsClassExpression(declaration) { return getAssignedName(declaration) } return nil } func GetImportClauseOfDeclaration(declaration *Declaration) *ImportClause { switch declaration.Kind { case KindImportDeclaration: return declaration.AsImportDeclaration().ImportClause.AsImportClause() case KindJSDocImportTag: return declaration.AsJSDocImportTag().ImportClause.AsImportClause() } return nil } func GetNonAssignedNameOfDeclaration(declaration *Node) *Node { // !!! switch declaration.Kind { case KindBinaryExpression: bin := declaration.AsBinaryExpression() kind := GetAssignmentDeclarationKind(bin) if kind == JSDeclarationKindProperty || kind == JSDeclarationKindThisProperty { if name := GetElementOrPropertyAccessName(bin.Left); name != nil { return name } else { return bin.Left } } return nil case KindExportAssignment, KindJSExportAssignment: expr := declaration.AsExportAssignment().Expression if IsIdentifier(expr) { return expr } return nil } return declaration.Name() } func getAssignedName(node *Node) *Node { parent := node.Parent if parent != nil { switch parent.Kind { case KindPropertyAssignment: return parent.AsPropertyAssignment().Name() case KindBindingElement: return parent.AsBindingElement().Name() case KindBinaryExpression: if node == parent.AsBinaryExpression().Right { left := parent.AsBinaryExpression().Left switch left.Kind { case KindIdentifier: return left case KindPropertyAccessExpression: return left.AsPropertyAccessExpression().Name() case KindElementAccessExpression: arg := SkipParentheses(left.AsElementAccessExpression().ArgumentExpression) if IsStringOrNumericLiteralLike(arg) { return arg } } } case KindCommonJSExport: return parent.AsCommonJSExport().Name() case KindVariableDeclaration: name := parent.AsVariableDeclaration().Name() if IsIdentifier(name) { return name } } } return nil } type JSDeclarationKind int const ( JSDeclarationKindNone JSDeclarationKind = iota /// module.exports = expr JSDeclarationKindModuleExports /// exports.name = expr /// module.exports.name = expr JSDeclarationKindExportsProperty /// className.prototype.name = expr JSDeclarationKindPrototypeProperty /// this.name = expr JSDeclarationKindThisProperty /// F.name = expr, F[name] = expr JSDeclarationKindProperty ) func GetAssignmentDeclarationKind(bin *BinaryExpression) JSDeclarationKind { if bin.OperatorToken.Kind != KindEqualsToken || !IsAccessExpression(bin.Left) { return JSDeclarationKindNone } if IsInJSFile(bin.Left) && IsModuleExportsAccessExpression(bin.Left) { return JSDeclarationKindModuleExports } else if IsInJSFile(bin.Left) && (IsModuleExportsAccessExpression(bin.Left.Expression()) || IsExportsIdentifier(bin.Left.Expression())) && GetElementOrPropertyAccessName(bin.Left) != nil { return JSDeclarationKindExportsProperty } if IsInJSFile(bin.Left) && bin.Left.Expression().Kind == KindThisKeyword { return JSDeclarationKindThisProperty } if bin.Left.Kind == KindPropertyAccessExpression && IsEntityNameExpressionEx(bin.Left.Expression(), IsInJSFile(bin.Left)) && IsIdentifier(bin.Left.Name()) || bin.Left.Kind == KindElementAccessExpression && IsEntityNameExpressionEx(bin.Left.Expression(), IsInJSFile(bin.Left)) { return JSDeclarationKindProperty } return JSDeclarationKindNone } /** * A declaration has a dynamic name if all of the following are true: * 1. The declaration has a computed property name. * 2. The computed name is *not* expressed as a StringLiteral. * 3. The computed name is *not* expressed as a NumericLiteral. * 4. The computed name is *not* expressed as a PlusToken or MinusToken * immediately followed by a NumericLiteral. */ func HasDynamicName(declaration *Node) bool { name := GetNameOfDeclaration(declaration) return name != nil && IsDynamicName(name) } func IsDynamicName(name *Node) bool { var expr *Node switch name.Kind { case KindComputedPropertyName: expr = name.AsComputedPropertyName().Expression case KindElementAccessExpression: expr = SkipParentheses(name.AsElementAccessExpression().ArgumentExpression) default: return false } return !IsStringOrNumericLiteralLike(expr) && !IsSignedNumericLiteral(expr) } func IsEntityNameExpression(node *Node) bool { return IsEntityNameExpressionEx(node, false /*allowJS*/) } func IsEntityNameExpressionEx(node *Node, allowJS bool) bool { if node.Kind == KindIdentifier || IsPropertyAccessEntityNameExpression(node, allowJS) { return true } if allowJS { return node.Kind == KindThisKeyword || isElementAccessEntityNameExpression(node, allowJS) } return false } func IsPropertyAccessEntityNameExpression(node *Node, allowJS bool) bool { if node.Kind == KindPropertyAccessExpression { expr := node.AsPropertyAccessExpression() return expr.Name().Kind == KindIdentifier && IsEntityNameExpressionEx(expr.Expression, allowJS) } return false } func isElementAccessEntityNameExpression(node *Node, allowJS bool) bool { if node.Kind == KindElementAccessExpression { expr := node.AsElementAccessExpression() if IsStringOrNumericLiteralLike(SkipParentheses(expr.ArgumentExpression)) { return IsEntityNameExpressionEx(expr.Expression, allowJS) } } return false } func IsDottedName(node *Node) bool { switch node.Kind { case KindIdentifier, KindThisKeyword, KindSuperKeyword, KindMetaProperty: return true case KindPropertyAccessExpression, KindParenthesizedExpression: return IsDottedName(node.Expression()) } return false } func HasSamePropertyAccessName(node1, node2 *Node) bool { if node1.Kind == KindIdentifier && node2.Kind == KindIdentifier { return node1.Text() == node2.Text() } else if node1.Kind == KindPropertyAccessExpression && node2.Kind == KindPropertyAccessExpression { return node1.AsPropertyAccessExpression().Name().Text() == node2.AsPropertyAccessExpression().Name().Text() && HasSamePropertyAccessName(node1.AsPropertyAccessExpression().Expression, node2.AsPropertyAccessExpression().Expression) } return false } func IsAmbientModule(node *Node) bool { return IsModuleDeclaration(node) && (node.AsModuleDeclaration().Name().Kind == KindStringLiteral || IsGlobalScopeAugmentation(node)) } func IsExternalModule(file *SourceFile) bool { return file.ExternalModuleIndicator != nil } func IsExternalOrCommonJSModule(file *SourceFile) bool { return file.ExternalModuleIndicator != nil || file.CommonJSModuleIndicator != nil } // TODO: Should we deprecate `IsExternalOrCommonJSModule` in favor of this function? func IsEffectiveExternalModule(node *SourceFile, compilerOptions *core.CompilerOptions) bool { return IsExternalModule(node) || (isCommonJSContainingModuleKind(compilerOptions.GetEmitModuleKind()) && node.CommonJSModuleIndicator != nil) } func isCommonJSContainingModuleKind(kind core.ModuleKind) bool { return kind == core.ModuleKindCommonJS || core.ModuleKindNode16 <= kind && kind <= core.ModuleKindNodeNext } func IsExternalModuleIndicator(node *Statement) bool { // Exported top-level member indicates moduleness return IsAnyImportOrReExport(node) || IsExportAssignment(node) || HasSyntacticModifier(node, ModifierFlagsExport) } func IsExportNamespaceAsDefaultDeclaration(node *Node) bool { if IsExportDeclaration(node) { decl := node.AsExportDeclaration() return IsNamespaceExport(decl.ExportClause) && ModuleExportNameIsDefault(decl.ExportClause.Name()) } return false } func IsGlobalScopeAugmentation(node *Node) bool { return IsModuleDeclaration(node) && node.AsModuleDeclaration().Keyword == KindGlobalKeyword } func IsModuleAugmentationExternal(node *Node) bool { // external module augmentation is a ambient module declaration that is either: // - defined in the top level scope and source file is an external module // - defined inside ambient module declaration located in the top level scope and source file not an external module switch node.Parent.Kind { case KindSourceFile: return IsExternalModule(node.Parent.AsSourceFile()) case KindModuleBlock: grandParent := node.Parent.Parent return IsAmbientModule(grandParent) && IsSourceFile(grandParent.Parent) && !IsExternalModule(grandParent.Parent.AsSourceFile()) } return false } func IsModuleWithStringLiteralName(node *Node) bool { return IsModuleDeclaration(node) && node.Name().Kind == KindStringLiteral } func GetContainingClass(node *Node) *Node { return FindAncestor(node.Parent, IsClassLike) } func GetExtendsHeritageClauseElement(node *Node) *ExpressionWithTypeArgumentsNode { return core.FirstOrNil(GetExtendsHeritageClauseElements(node)) } func GetExtendsHeritageClauseElements(node *Node) []*ExpressionWithTypeArgumentsNode { return GetHeritageElements(node, KindExtendsKeyword) } func GetImplementsHeritageClauseElements(node *Node) []*ExpressionWithTypeArgumentsNode { return GetHeritageElements(node, KindImplementsKeyword) } func GetHeritageElements(node *Node, kind Kind) []*Node { clause := GetHeritageClause(node, kind) if clause != nil { return clause.AsHeritageClause().Types.Nodes } return nil } func GetHeritageClause(node *Node, kind Kind) *Node { clauses := getHeritageClauses(node) if clauses != nil { for _, clause := range clauses.Nodes { if clause.AsHeritageClause().Token == kind { return clause } } } return nil } func getHeritageClauses(node *Node) *NodeList { switch node.Kind { case KindClassDeclaration: return node.AsClassDeclaration().HeritageClauses case KindClassExpression: return node.AsClassExpression().HeritageClauses case KindInterfaceDeclaration: return node.AsInterfaceDeclaration().HeritageClauses } return nil } func IsPartOfTypeQuery(node *Node) bool { for node.Kind == KindQualifiedName || node.Kind == KindIdentifier { node = node.Parent } return node.Kind == KindTypeQuery } /** * This function returns true if the this node's root declaration is a parameter. * For example, passing a `ParameterDeclaration` will return true, as will passing a * binding element that is a child of a `ParameterDeclaration`. * * If you are looking to test that a `Node` is a `ParameterDeclaration`, use `isParameter`. */ func IsPartOfParameterDeclaration(node *Node) bool { return GetRootDeclaration(node).Kind == KindParameter } func IsInTopLevelContext(node *Node) bool { // The name of a class or function declaration is a BindingIdentifier in its surrounding scope. if IsIdentifier(node) { parent := node.Parent if (IsClassDeclaration(parent) || IsFunctionDeclaration(parent)) && parent.Name() == node { node = parent } } container := GetThisContainer(node, true /*includeArrowFunctions*/, false /*includeClassComputedPropertyName*/) return IsSourceFile(container) } func GetThisContainer(node *Node, includeArrowFunctions bool, includeClassComputedPropertyName bool) *Node { for { node = node.Parent if node == nil { panic("nil parent in getThisContainer") } switch node.Kind { case KindComputedPropertyName: if includeClassComputedPropertyName && IsClassLike(node.Parent.Parent) { return node } node = node.Parent.Parent case KindDecorator: if node.Parent.Kind == KindParameter && IsClassElement(node.Parent.Parent) { // If the decorator's parent is a Parameter, we resolve the this container from // the grandparent class declaration. node = node.Parent.Parent } else if IsClassElement(node.Parent) { // If the decorator's parent is a class element, we resolve the 'this' container // from the parent class declaration. node = node.Parent } case KindArrowFunction: if includeArrowFunctions { return node } case KindFunctionDeclaration, KindFunctionExpression, KindModuleDeclaration, KindClassStaticBlockDeclaration, KindPropertyDeclaration, KindPropertySignature, KindMethodDeclaration, KindMethodSignature, KindConstructor, KindGetAccessor, KindSetAccessor, KindCallSignature, KindConstructSignature, KindIndexSignature, KindEnumDeclaration, KindSourceFile: return node } } } func GetSuperContainer(node *Node, stopOnFunctions bool) *Node { for node = node.Parent; node != nil; node = node.Parent { switch node.Kind { case KindComputedPropertyName: node = node.Parent case KindFunctionDeclaration, KindFunctionExpression, KindArrowFunction: if !stopOnFunctions { continue } return node case KindPropertyDeclaration, KindPropertySignature, KindMethodDeclaration, KindMethodSignature, KindConstructor, KindGetAccessor, KindSetAccessor, KindClassStaticBlockDeclaration: return node case KindDecorator: // Decorators are always applied outside of the body of a class or method. if node.Parent.Kind == KindParameter && IsClassElement(node.Parent.Parent) { // If the decorator's parent is a Parameter, we resolve the this container from // the grandparent class declaration. node = node.Parent.Parent } else if IsClassElement(node.Parent) { // If the decorator's parent is a class element, we resolve the 'this' container // from the parent class declaration. node = node.Parent } } } return nil } func GetImmediatelyInvokedFunctionExpression(fn *Node) *Node { if IsFunctionExpressionOrArrowFunction(fn) { prev := fn parent := fn.Parent for IsParenthesizedExpression(parent) { prev = parent parent = parent.Parent } if IsCallExpression(parent) && parent.AsCallExpression().Expression == prev { return parent } } return nil } func IsEnumConst(node *Node) bool { return GetCombinedModifierFlags(node)&ModifierFlagsConst != 0 } func ExportAssignmentIsAlias(node *Node) bool { e := node.AsExportAssignment().Expression return IsEntityNameExpression(e) || IsClassExpression(e) } func IsInstanceOfExpression(node *Node) bool { return IsBinaryExpression(node) && node.AsBinaryExpression().OperatorToken.Kind == KindInstanceOfKeyword } func IsAnyImportOrReExport(node *Node) bool { return IsAnyImportSyntax(node) || IsExportDeclaration(node) } func IsAnyImportSyntax(node *Node) bool { return NodeKindIs(node, KindImportDeclaration, KindJSImportDeclaration, KindImportEqualsDeclaration) } func IsJsonSourceFile(file *SourceFile) bool { return file.ScriptKind == core.ScriptKindJSON } func IsInJsonFile(node *Node) bool { return node.Flags&NodeFlagsJsonFile != 0 } func GetExternalModuleName(node *Node) *Expression { switch node.Kind { case KindImportDeclaration, KindJSImportDeclaration: return node.AsImportDeclaration().ModuleSpecifier case KindExportDeclaration: return node.AsExportDeclaration().ModuleSpecifier case KindImportEqualsDeclaration: if node.AsImportEqualsDeclaration().ModuleReference.Kind == KindExternalModuleReference { return node.AsImportEqualsDeclaration().ModuleReference.AsExternalModuleReference().Expression } return nil case KindImportType: return getImportTypeNodeLiteral(node) case KindCallExpression: return core.FirstOrNil(node.AsCallExpression().Arguments.Nodes) case KindModuleDeclaration: if IsStringLiteral(node.AsModuleDeclaration().Name()) { return node.AsModuleDeclaration().Name() } return nil } panic("Unhandled case in getExternalModuleName") } func GetImportAttributes(node *Node) *Node { switch node.Kind { case KindImportDeclaration, KindJSImportDeclaration: return node.AsImportDeclaration().Attributes case KindExportDeclaration: return node.AsExportDeclaration().Attributes } panic("Unhandled case in getImportAttributes") } func getImportTypeNodeLiteral(node *Node) *Node { if IsImportTypeNode(node) { importTypeNode := node.AsImportTypeNode() if IsLiteralTypeNode(importTypeNode.Argument) { literalTypeNode := importTypeNode.Argument.AsLiteralTypeNode() if IsStringLiteral(literalTypeNode.Literal) { return literalTypeNode.Literal } } } return nil } func IsExpressionNode(node *Node) bool { switch node.Kind { case KindSuperKeyword, KindNullKeyword, KindTrueKeyword, KindFalseKeyword, KindRegularExpressionLiteral, KindArrayLiteralExpression, KindObjectLiteralExpression, KindPropertyAccessExpression, KindElementAccessExpression, KindCallExpression, KindNewExpression, KindTaggedTemplateExpression, KindAsExpression, KindTypeAssertionExpression, KindSatisfiesExpression, KindNonNullExpression, KindParenthesizedExpression, KindFunctionExpression, KindClassExpression, KindArrowFunction, KindVoidExpression, KindDeleteExpression, KindTypeOfExpression, KindPrefixUnaryExpression, KindPostfixUnaryExpression, KindBinaryExpression, KindConditionalExpression, KindSpreadElement, KindTemplateExpression, KindOmittedExpression, KindJsxElement, KindJsxSelfClosingElement, KindJsxFragment, KindYieldExpression, KindAwaitExpression: return true case KindMetaProperty: // `import.defer` in `import.defer(...)` is not an expression return !IsImportCall(node.Parent) || node.Parent.AsCallExpression().Expression != node case KindExpressionWithTypeArguments: return !IsHeritageClause(node.Parent) case KindQualifiedName: for node.Parent.Kind == KindQualifiedName { node = node.Parent } return IsTypeQueryNode(node.Parent) || IsJSDocLinkLike(node.Parent) || IsJSDocNameReference(node.Parent) || isJSXTagName(node) case KindPrivateIdentifier: return IsBinaryExpression(node.Parent) && node.Parent.AsBinaryExpression().Left == node && node.Parent.AsBinaryExpression().OperatorToken.Kind == KindInKeyword case KindIdentifier: if IsTypeQueryNode(node.Parent) || IsJSDocLinkLike(node.Parent) || IsJSDocNameReference(node.Parent) || isJSXTagName(node) { return true } fallthrough case KindNumericLiteral, KindBigIntLiteral, KindStringLiteral, KindNoSubstitutionTemplateLiteral, KindThisKeyword: return IsInExpressionContext(node) default: return false } } func IsInExpressionContext(node *Node) bool { parent := node.Parent switch parent.Kind { case KindVariableDeclaration: return parent.AsVariableDeclaration().Initializer == node case KindParameter: return parent.AsParameterDeclaration().Initializer == node case KindPropertyDeclaration: return parent.AsPropertyDeclaration().Initializer == node case KindPropertySignature: return parent.AsPropertySignatureDeclaration().Initializer == node case KindEnumMember: return parent.AsEnumMember().Initializer == node case KindPropertyAssignment: return parent.AsPropertyAssignment().Initializer == node case KindBindingElement: return parent.AsBindingElement().Initializer == node case KindExpressionStatement: return parent.AsExpressionStatement().Expression == node case KindIfStatement: return parent.AsIfStatement().Expression == node case KindDoStatement: return parent.AsDoStatement().Expression == node case KindWhileStatement: return parent.AsWhileStatement().Expression == node case KindReturnStatement: return parent.AsReturnStatement().Expression == node case KindWithStatement: return parent.AsWithStatement().Expression == node case KindSwitchStatement: return parent.AsSwitchStatement().Expression == node case KindCaseClause, KindDefaultClause: return parent.AsCaseOrDefaultClause().Expression == node case KindThrowStatement: return parent.AsThrowStatement().Expression == node case KindForStatement: s := parent.AsForStatement() return s.Initializer == node && s.Initializer.Kind != KindVariableDeclarationList || s.Condition == node || s.Incrementor == node case KindForInStatement, KindForOfStatement: s := parent.AsForInOrOfStatement() return s.Initializer == node && s.Initializer.Kind != KindVariableDeclarationList || s.Expression == node case KindTypeAssertionExpression: return parent.AsTypeAssertion().Expression == node case KindAsExpression: return parent.AsAsExpression().Expression == node case KindTemplateSpan: return parent.AsTemplateSpan().Expression == node case KindComputedPropertyName: return parent.AsComputedPropertyName().Expression == node case KindDecorator, KindJsxExpression, KindJsxSpreadAttribute, KindSpreadAssignment: return true case KindExpressionWithTypeArguments: return parent.AsExpressionWithTypeArguments().Expression == node && !IsPartOfTypeNode(parent) case KindShorthandPropertyAssignment: return parent.AsShorthandPropertyAssignment().ObjectAssignmentInitializer == node case KindSatisfiesExpression: return parent.AsSatisfiesExpression().Expression == node default: return IsExpressionNode(parent) } } func IsPartOfTypeNode(node *Node) bool { kind := node.Kind if kind >= KindFirstTypeNode && kind <= KindLastTypeNode { return true } switch node.Kind { case KindAnyKeyword, KindUnknownKeyword, KindNumberKeyword, KindBigIntKeyword, KindStringKeyword, KindBooleanKeyword, KindSymbolKeyword, KindObjectKeyword, KindUndefinedKeyword, KindNullKeyword, KindNeverKeyword: return true case KindVoidKeyword: return node.Parent.Kind != KindVoidExpression case KindExpressionWithTypeArguments: return isPartOfTypeExpressionWithTypeArguments(node) case KindTypeParameter: return node.Parent.Kind == KindMappedType || node.Parent.Kind == KindInferType case KindIdentifier: parent := node.Parent if IsQualifiedName(parent) && parent.AsQualifiedName().Right == node { return isPartOfTypeNodeInParent(parent) } if IsPropertyAccessExpression(parent) && parent.AsPropertyAccessExpression().Name() == node { return isPartOfTypeNodeInParent(parent) } return isPartOfTypeNodeInParent(node) case KindQualifiedName, KindPropertyAccessExpression, KindThisKeyword: return isPartOfTypeNodeInParent(node) } return false } func isPartOfTypeNodeInParent(node *Node) bool { parent := node.Parent if parent.Kind == KindTypeQuery { return false } if parent.Kind == KindImportType { return !parent.AsImportTypeNode().IsTypeOf } // Do not recursively call isPartOfTypeNode on the parent. In the example: // // let a: A.B.C; // // Calling isPartOfTypeNode would consider the qualified name A.B a type node. // Only C and A.B.C are type nodes. if parent.Kind >= KindFirstTypeNode && parent.Kind <= KindLastTypeNode { return true } switch parent.Kind { case KindExpressionWithTypeArguments: return isPartOfTypeExpressionWithTypeArguments(parent) case KindTypeParameter: return node == parent.AsTypeParameter().Constraint case KindVariableDeclaration, KindParameter, KindPropertyDeclaration, KindPropertySignature, KindFunctionDeclaration, KindFunctionExpression, KindArrowFunction, KindConstructor, KindMethodDeclaration, KindMethodSignature, KindGetAccessor, KindSetAccessor, KindCallSignature, KindConstructSignature, KindIndexSignature, KindTypeAssertionExpression: return node == parent.Type() case KindCallExpression, KindNewExpression, KindTaggedTemplateExpression: return slices.Contains(parent.TypeArguments(), node) } return false } func isPartOfTypeExpressionWithTypeArguments(node *Node) bool { parent := node.Parent return IsHeritageClause(parent) && (!IsClassLike(parent.Parent) || parent.AsHeritageClause().Token == KindImplementsKeyword) || IsJSDocImplementsTag(parent) || IsJSDocAugmentsTag(parent) } func IsJSDocLinkLike(node *Node) bool { return NodeKindIs(node, KindJSDocLink, KindJSDocLinkCode, KindJSDocLinkPlain) } func IsJSDocTag(node *Node) bool { return node.Kind >= KindFirstJSDocTagNode && node.Kind <= KindLastJSDocTagNode } func isJSXTagName(node *Node) bool { parent := node.Parent switch parent.Kind { case KindJsxOpeningElement: return parent.AsJsxOpeningElement().TagName == node case KindJsxSelfClosingElement: return parent.AsJsxSelfClosingElement().TagName == node case KindJsxClosingElement: return parent.AsJsxClosingElement().TagName == node } return false } func IsSuperCall(node *Node) bool { return IsCallExpression(node) && node.AsCallExpression().Expression.Kind == KindSuperKeyword } func IsImportCall(node *Node) bool { if !IsCallExpression(node) { return false } e := node.AsCallExpression().Expression return e.Kind == KindImportKeyword || IsMetaProperty(e) && e.AsMetaProperty().KeywordToken == KindImportKeyword && e.Text() == "defer" } func IsComputedNonLiteralName(name *Node) bool { return IsComputedPropertyName(name) && !IsStringOrNumericLiteralLike(name.Expression()) } func IsQuestionToken(node *Node) bool { return node != nil && node.Kind == KindQuestionToken } func GetTextOfPropertyName(name *Node) string { text, _ := TryGetTextOfPropertyName(name) return text } func TryGetTextOfPropertyName(name *Node) (string, bool) { switch name.Kind { case KindIdentifier, KindPrivateIdentifier, KindStringLiteral, KindNumericLiteral, KindBigIntLiteral, KindNoSubstitutionTemplateLiteral: return name.Text(), true case KindComputedPropertyName: if IsStringOrNumericLiteralLike(name.Expression()) { return name.Expression().Text(), true } case KindJsxNamespacedName: return name.AsJsxNamespacedName().Namespace.Text() + ":" + name.Name().Text(), true } return "", false } func IsJSDocNode(node *Node) bool { return node.Kind >= KindFirstJSDocNode && node.Kind <= KindLastJSDocNode } func IsNonWhitespaceToken(node *Node) bool { return IsTokenKind(node.Kind) && !IsWhitespaceOnlyJsxText(node) } func IsWhitespaceOnlyJsxText(node *Node) bool { return node.Kind == KindJsxText && node.AsJsxText().ContainsOnlyTriviaWhiteSpaces } func GetNewTargetContainer(node *Node) *Node { container := GetThisContainer(node, false /*includeArrowFunctions*/, false /*includeClassComputedPropertyName*/) if container != nil { switch container.Kind { case KindConstructor, KindFunctionDeclaration, KindFunctionExpression: return container } } return nil } func GetEnclosingBlockScopeContainer(node *Node) *Node { return FindAncestor(node.Parent, func(current *Node) bool { return IsBlockScope(current, current.Parent) }) } func IsBlockScope(node *Node, parentNode *Node) bool { switch node.Kind { case KindSourceFile, KindCaseBlock, KindCatchClause, KindModuleDeclaration, KindForStatement, KindForInStatement, KindForOfStatement, KindConstructor, KindMethodDeclaration, KindGetAccessor, KindSetAccessor, KindFunctionDeclaration, KindFunctionExpression, KindArrowFunction, KindPropertyDeclaration, KindClassStaticBlockDeclaration: return true case KindBlock: // function block is not considered block-scope container // see comment in binder.ts: bind(...), case for SyntaxKind.Block return !IsFunctionLikeOrClassStaticBlockDeclaration(parentNode) } return false } type SemanticMeaning int32 const ( SemanticMeaningNone SemanticMeaning = 0 SemanticMeaningValue SemanticMeaning = 1 << 0 SemanticMeaningType SemanticMeaning = 1 << 1 SemanticMeaningNamespace SemanticMeaning = 1 << 2 SemanticMeaningAll SemanticMeaning = SemanticMeaningValue | SemanticMeaningType | SemanticMeaningNamespace ) func GetMeaningFromDeclaration(node *Node) SemanticMeaning { switch node.Kind { case KindVariableDeclaration: return SemanticMeaningValue case KindParameter, KindBindingElement, KindPropertyDeclaration, KindPropertySignature, KindPropertyAssignment, KindShorthandPropertyAssignment, KindMethodDeclaration, KindMethodSignature, KindConstructor, KindGetAccessor, KindSetAccessor, KindFunctionDeclaration, KindFunctionExpression, KindArrowFunction, KindCatchClause, KindJsxAttribute: return SemanticMeaningValue case KindTypeParameter, KindInterfaceDeclaration, KindTypeAliasDeclaration, KindJSTypeAliasDeclaration, KindTypeLiteral: return SemanticMeaningType case KindEnumMember, KindClassDeclaration: return SemanticMeaningValue | SemanticMeaningType case KindModuleDeclaration: if IsAmbientModule(node) { return SemanticMeaningNamespace | SemanticMeaningValue } else if GetModuleInstanceState(node) == ModuleInstanceStateInstantiated { return SemanticMeaningNamespace | SemanticMeaningValue } else { return SemanticMeaningNamespace } case KindEnumDeclaration, KindNamedImports, KindImportSpecifier, KindImportEqualsDeclaration, KindImportDeclaration, KindJSImportDeclaration, KindExportAssignment, KindJSExportAssignment, KindExportDeclaration: return SemanticMeaningAll // An external module can be a Value case KindSourceFile: return SemanticMeaningNamespace | SemanticMeaningValue } return SemanticMeaningAll } func IsPropertyAccessOrQualifiedName(node *Node) bool { return node.Kind == KindPropertyAccessExpression || node.Kind == KindQualifiedName } func IsLabelName(node *Node) bool { return IsLabelOfLabeledStatement(node) || IsJumpStatementTarget(node) } func IsLabelOfLabeledStatement(node *Node) bool { if !IsIdentifier(node) { return false } if !IsLabeledStatement(node.Parent) { return false } return node == node.Parent.Label() } func IsJumpStatementTarget(node *Node) bool { if !IsIdentifier(node) { return false } if !IsBreakOrContinueStatement(node.Parent) { return false } return node == node.Parent.Label() } func IsBreakOrContinueStatement(node *Node) bool { return NodeKindIs(node, KindBreakStatement, KindContinueStatement) } // GetModuleInstanceState is used during binding as well as in transformations and tests, and therefore may be invoked // with a node that does not yet have its `Parent` pointer set. In this case, an `ancestors` represents a stack of // virtual `Parent` pointers that can be used to walk up the tree. Since `getModuleInstanceStateForAliasTarget` may // potentially walk up out of the provided `Node`, merely setting the parent pointers for a given `ModuleDeclaration` // prior to invoking `GetModuleInstanceState` is not sufficient. It is, however, necessary that the `Parent` pointers // for all ancestors of the `Node` provided to `GetModuleInstanceState` have been set. // Push a virtual parent pointer onto `ancestors` and return it. func pushAncestor(ancestors []*Node, parent *Node) []*Node { return append(ancestors, parent) } // If a virtual `Parent` exists on the stack, returns the previous stack entry and the virtual `Parent“. // Otherwise, we return `nil` and the value of `node.Parent`. func popAncestor(ancestors []*Node, node *Node) ([]*Node, *Node) { if len(ancestors) == 0 { return nil, node.Parent } n := len(ancestors) - 1 return ancestors[:n], ancestors[n] } type ModuleInstanceState int32 const ( ModuleInstanceStateUnknown ModuleInstanceState = iota ModuleInstanceStateNonInstantiated ModuleInstanceStateInstantiated ModuleInstanceStateConstEnumOnly ) func GetModuleInstanceState(node *Node) ModuleInstanceState { return getModuleInstanceState(node, nil, nil) } func getModuleInstanceState(node *Node, ancestors []*Node, visited map[NodeId]ModuleInstanceState) ModuleInstanceState { module := node.AsModuleDeclaration() if module.Body != nil { return getModuleInstanceStateCached(module.Body, pushAncestor(ancestors, node), visited) } else { return ModuleInstanceStateInstantiated } } func getModuleInstanceStateCached(node *Node, ancestors []*Node, visited map[NodeId]ModuleInstanceState) ModuleInstanceState { if visited == nil { visited = make(map[NodeId]ModuleInstanceState) } nodeId := GetNodeId(node) if cached, ok := visited[nodeId]; ok { if cached != ModuleInstanceStateUnknown { return cached } return ModuleInstanceStateNonInstantiated } visited[nodeId] = ModuleInstanceStateUnknown result := getModuleInstanceStateWorker(node, ancestors, visited) visited[nodeId] = result return result } func getModuleInstanceStateWorker(node *Node, ancestors []*Node, visited map[NodeId]ModuleInstanceState) ModuleInstanceState { // A module is uninstantiated if it contains only switch node.Kind { case KindInterfaceDeclaration, KindTypeAliasDeclaration, KindJSTypeAliasDeclaration: return ModuleInstanceStateNonInstantiated case KindEnumDeclaration: if IsEnumConst(node) { return ModuleInstanceStateConstEnumOnly } case KindImportDeclaration, KindJSImportDeclaration, KindImportEqualsDeclaration: if !HasSyntacticModifier(node, ModifierFlagsExport) { return ModuleInstanceStateNonInstantiated } case KindExportDeclaration: decl := node.AsExportDeclaration() if decl.ModuleSpecifier == nil && decl.ExportClause != nil && decl.ExportClause.Kind == KindNamedExports { state := ModuleInstanceStateNonInstantiated ancestors = pushAncestor(ancestors, node) ancestors = pushAncestor(ancestors, decl.ExportClause) for _, specifier := range decl.ExportClause.AsNamedExports().Elements.Nodes { specifierState := getModuleInstanceStateForAliasTarget(specifier, ancestors, visited) if specifierState > state { state = specifierState } if state == ModuleInstanceStateInstantiated { return state } } return state } case KindModuleBlock: state := ModuleInstanceStateNonInstantiated ancestors = pushAncestor(ancestors, node) node.ForEachChild(func(n *Node) bool { childState := getModuleInstanceStateCached(n, ancestors, visited) switch childState { case ModuleInstanceStateNonInstantiated: return false case ModuleInstanceStateConstEnumOnly: state = ModuleInstanceStateConstEnumOnly return false case ModuleInstanceStateInstantiated: state = ModuleInstanceStateInstantiated return true } panic("Unhandled case in getModuleInstanceStateWorker") }) return state case KindModuleDeclaration: return getModuleInstanceState(node, ancestors, visited) } return ModuleInstanceStateInstantiated } func getModuleInstanceStateForAliasTarget(node *Node, ancestors []*Node, visited map[NodeId]ModuleInstanceState) ModuleInstanceState { spec := node.AsExportSpecifier() name := spec.PropertyName if name == nil { name = spec.Name() } if name.Kind != KindIdentifier { // Skip for invalid syntax like this: export { "x" } return ModuleInstanceStateInstantiated } for ancestors, p := popAncestor(ancestors, node); p != nil; ancestors, p = popAncestor(ancestors, p) { if IsBlock(p) || IsModuleBlock(p) || IsSourceFile(p) { statements := GetStatementsOfBlock(p) found := ModuleInstanceStateUnknown statementsAncestors := pushAncestor(ancestors, p) for _, statement := range statements.Nodes { if NodeHasName(statement, name) { state := getModuleInstanceStateCached(statement, statementsAncestors, visited) if found == ModuleInstanceStateUnknown || state > found { found = state } if found == ModuleInstanceStateInstantiated { return found } if statement.Kind == KindImportEqualsDeclaration { // Treat re-exports of import aliases as instantiated since they're ambiguous. This is consistent // with `export import x = mod.x` being treated as instantiated: // import x = mod.x; // export { x }; found = ModuleInstanceStateInstantiated } } } if found != ModuleInstanceStateUnknown { return found } } } // Couldn't locate, assume could refer to a value return ModuleInstanceStateInstantiated } func NodeHasName(statement *Node, id *Node) bool { name := statement.Name() if name != nil { return IsIdentifier(name) && name.AsIdentifier().Text == id.AsIdentifier().Text } if IsVariableStatement(statement) { declarations := statement.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes return core.Some(declarations, func(d *Node) bool { return NodeHasName(d, id) }) } return false } func IsInternalModuleImportEqualsDeclaration(node *Node) bool { return IsImportEqualsDeclaration(node) && node.AsImportEqualsDeclaration().ModuleReference.Kind != KindExternalModuleReference } func GetAssertedTypeNode(node *Node) *Node { switch node.Kind { case KindAsExpression: return node.AsAsExpression().Type case KindSatisfiesExpression: return node.AsSatisfiesExpression().Type case KindTypeAssertionExpression: return node.AsTypeAssertion().Type } panic("Unhandled case in getAssertedTypeNode") } func IsConstAssertion(node *Node) bool { switch node.Kind { case KindAsExpression, KindTypeAssertionExpression: return IsConstTypeReference(GetAssertedTypeNode(node)) } return false } func IsConstTypeReference(node *Node) bool { return IsTypeReferenceNode(node) && len(node.TypeArguments()) == 0 && IsIdentifier(node.AsTypeReferenceNode().TypeName) && node.AsTypeReferenceNode().TypeName.Text() == "const" } func IsGlobalSourceFile(node *Node) bool { return node.Kind == KindSourceFile && !IsExternalOrCommonJSModule(node.AsSourceFile()) } func IsParameterLike(node *Node) bool { switch node.Kind { case KindParameter, KindTypeParameter: return true } return false } func GetDeclarationOfKind(symbol *Symbol, kind Kind) *Node { for _, declaration := range symbol.Declarations { if declaration.Kind == kind { return declaration } } return nil } func FindConstructorDeclaration(node *ClassLikeDeclaration) *Node { for _, member := range node.ClassLikeData().Members.Nodes { if IsConstructorDeclaration(member) && NodeIsPresent(member.AsConstructorDeclaration().Body) { return member } } return nil } func GetFirstIdentifier(node *Node) *Node { switch node.Kind { case KindIdentifier: return node case KindQualifiedName: return GetFirstIdentifier(node.AsQualifiedName().Left) case KindPropertyAccessExpression: return GetFirstIdentifier(node.AsPropertyAccessExpression().Expression) } panic("Unhandled case in GetFirstIdentifier") } func GetNamespaceDeclarationNode(node *Node) *Node { switch node.Kind { case KindImportDeclaration, KindJSImportDeclaration: importClause := node.AsImportDeclaration().ImportClause if importClause != nil && importClause.AsImportClause().NamedBindings != nil && IsNamespaceImport(importClause.AsImportClause().NamedBindings) { return importClause.AsImportClause().NamedBindings } case KindImportEqualsDeclaration: return node case KindExportDeclaration: exportClause := node.AsExportDeclaration().ExportClause if exportClause != nil && IsNamespaceExport(exportClause) { return exportClause } default: panic("Unhandled case in getNamespaceDeclarationNode") } return nil } func ModuleExportNameIsDefault(node *Node) bool { return node.Text() == InternalSymbolNameDefault } func IsDefaultImport(node *Node /*ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration*/) bool { switch node.Kind { case KindImportDeclaration, KindJSImportDeclaration: importClause := node.AsImportDeclaration().ImportClause return importClause != nil && importClause.AsImportClause().name != nil } return false } func GetImpliedNodeFormatForFile(path string, packageJsonType string) core.ModuleKind { impliedNodeFormat := core.ResolutionModeNone if tspath.FileExtensionIsOneOf(path, []string{tspath.ExtensionDmts, tspath.ExtensionMts, tspath.ExtensionMjs}) { impliedNodeFormat = core.ResolutionModeESM } else if tspath.FileExtensionIsOneOf(path, []string{tspath.ExtensionDcts, tspath.ExtensionCts, tspath.ExtensionCjs}) { impliedNodeFormat = core.ResolutionModeCommonJS } else if tspath.FileExtensionIsOneOf(path, []string{tspath.ExtensionDts, tspath.ExtensionTs, tspath.ExtensionTsx, tspath.ExtensionJs, tspath.ExtensionJsx}) { impliedNodeFormat = core.IfElse(packageJsonType == "module", core.ResolutionModeESM, core.ResolutionModeCommonJS) } return impliedNodeFormat } func GetEmitModuleFormatOfFileWorker(fileName string, options *core.CompilerOptions, sourceFileMetaData SourceFileMetaData) core.ModuleKind { result := GetImpliedNodeFormatForEmitWorker(fileName, options.GetEmitModuleKind(), sourceFileMetaData) if result != core.ModuleKindNone { return result } return options.GetEmitModuleKind() } func GetImpliedNodeFormatForEmitWorker(fileName string, emitModuleKind core.ModuleKind, sourceFileMetaData SourceFileMetaData) core.ResolutionMode { if core.ModuleKindNode16 <= emitModuleKind && emitModuleKind <= core.ModuleKindNodeNext { return sourceFileMetaData.ImpliedNodeFormat } if sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindCommonJS && (sourceFileMetaData.PackageJsonType == "commonjs" || tspath.FileExtensionIsOneOf(fileName, []string{tspath.ExtensionCjs, tspath.ExtensionCts})) { return core.ModuleKindCommonJS } if sourceFileMetaData.ImpliedNodeFormat == core.ModuleKindESNext && (sourceFileMetaData.PackageJsonType == "module" || tspath.FileExtensionIsOneOf(fileName, []string{tspath.ExtensionMjs, tspath.ExtensionMts})) { return core.ModuleKindESNext } return core.ModuleKindNone } func GetDeclarationContainer(node *Node) *Node { return FindAncestor(GetRootDeclaration(node), func(node *Node) bool { switch node.Kind { case KindVariableDeclaration, KindVariableDeclarationList, KindImportSpecifier, KindNamedImports, KindNamespaceImport, KindImportClause: return false default: return true } }).Parent } // Indicates that a symbol is an alias that does not merge with a local declaration. // OR Is a JSContainer which may merge an alias with a local declaration func IsNonLocalAlias(symbol *Symbol, excludes SymbolFlags) bool { if symbol == nil { return false } return symbol.Flags&(SymbolFlagsAlias|excludes) == SymbolFlagsAlias || symbol.Flags&SymbolFlagsAlias != 0 && symbol.Flags&SymbolFlagsAssignment != 0 } // An alias symbol is created by one of the following declarations: // // import = ... // const = ... (JS only) // const { , ... } = ... (JS only) // import from ... // import * as from ... // import { x as } from ... // export { x as } from ... // export * as ns from ... // export = // export default // module.exports = (JS only) func IsAliasSymbolDeclaration(node *Node) bool { switch node.Kind { case KindImportEqualsDeclaration, KindNamespaceExportDeclaration, KindNamespaceImport, KindNamespaceExport, KindImportSpecifier, KindExportSpecifier: return true case KindImportClause: return node.AsImportClause().Name() != nil case KindExportAssignment, KindJSExportAssignment: return ExportAssignmentIsAlias(node) case KindVariableDeclaration, KindBindingElement: return IsVariableDeclarationInitializedToRequire(node) } return false } func IsParseTreeNode(node *Node) bool { return node.Flags&NodeFlagsSynthesized == 0 } // Returns a token if position is in [start-of-leading-trivia, end), includes JSDoc only if requested func GetNodeAtPosition(file *SourceFile, position int, includeJSDoc bool) *Node { current := file.AsNode() for { var child *Node if includeJSDoc { for _, jsdoc := range current.JSDoc(file) { if nodeContainsPosition(jsdoc, position) { child = jsdoc break } } } if child == nil { current.ForEachChild(func(node *Node) bool { if nodeContainsPosition(node, position) { child = node return true } return false }) } if child == nil || IsMetaProperty(child) { return current } current = child } } func nodeContainsPosition(node *Node, position int) bool { return node.Kind >= KindFirstNode && node.Pos() <= position && (position < node.End() || position == node.End() && node.Kind == KindEndOfFile) } func findImportOrRequire(text string, start int) (index int, size int) { index = max(start, 0) n := len(text) for index < n { next := strings.IndexAny(text[index:], "ir") if next < 0 { break } index += next var expected string if text[index] == 'i' { size = 6 expected = "import" } else { size = 7 expected = "require" } if index+size <= n && text[index:index+size] == expected { return index, size } index++ } return -1, 0 } func ForEachDynamicImportOrRequireCall( file *SourceFile, includeTypeSpaceImports bool, requireStringLiteralLikeArgument bool, cb func(node *Node, argument *Expression) bool, ) bool { isJavaScriptFile := IsInJSFile(file.AsNode()) lastIndex, size := findImportOrRequire(file.Text(), 0) for lastIndex >= 0 { node := GetNodeAtPosition(file, lastIndex, isJavaScriptFile && includeTypeSpaceImports) if isJavaScriptFile && IsRequireCall(node, requireStringLiteralLikeArgument) { if cb(node, node.Arguments()[0]) { return true } } else if IsImportCall(node) && len(node.Arguments()) > 0 && (!requireStringLiteralLikeArgument || IsStringLiteralLike(node.Arguments()[0])) { if cb(node, node.Arguments()[0]) { return true } } else if includeTypeSpaceImports && IsLiteralImportTypeNode(node) { if cb(node, node.AsImportTypeNode().Argument.AsLiteralTypeNode().Literal) { return true } } // skip past import/require lastIndex += size lastIndex, size = findImportOrRequire(file.Text(), lastIndex) } return false } // Returns true if the node is a CallExpression to the identifier 'require' with // exactly one argument (of the form 'require("name")'). // This function does not test if the node is in a JavaScript file or not. func IsRequireCall(node *Node, requireStringLiteralLikeArgument bool) bool { if !IsCallExpression(node) { return false } call := node.AsCallExpression() if !IsIdentifier(call.Expression) || call.Expression.Text() != "require" { return false } if len(call.Arguments.Nodes) != 1 { return false } return !requireStringLiteralLikeArgument || IsStringLiteralLike(call.Arguments.Nodes[0]) } func IsRequireVariableStatement(node *Node) bool { if IsVariableStatement(node) { if declarations := node.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes; len(declarations) > 0 { return core.Every(declarations, IsVariableDeclarationInitializedToRequire) } } return false } func GetJSXImplicitImportBase(compilerOptions *core.CompilerOptions, file *SourceFile) string { jsxImportSourcePragma := GetPragmaFromSourceFile(file, "jsximportsource") jsxRuntimePragma := GetPragmaFromSourceFile(file, "jsxruntime") if GetPragmaArgument(jsxRuntimePragma, "factory") == "classic" { return "" } if compilerOptions.Jsx == core.JsxEmitReactJSX || compilerOptions.Jsx == core.JsxEmitReactJSXDev || compilerOptions.JsxImportSource != "" || jsxImportSourcePragma != nil || GetPragmaArgument(jsxRuntimePragma, "factory") == "automatic" { result := GetPragmaArgument(jsxImportSourcePragma, "factory") if result == "" { result = compilerOptions.JsxImportSource } if result == "" { result = "react" } return result } return "" } func GetJSXRuntimeImport(base string, options *core.CompilerOptions) string { if base == "" { return base } return base + "/" + core.IfElse(options.Jsx == core.JsxEmitReactJSXDev, "jsx-dev-runtime", "jsx-runtime") } func GetPragmaFromSourceFile(file *SourceFile, name string) *Pragma { var result *Pragma if file != nil { for i := range file.Pragmas { if file.Pragmas[i].Name == name { result = &file.Pragmas[i] // Last one wins } } } return result } func GetPragmaArgument(pragma *Pragma, name string) string { if pragma != nil { if arg, ok := pragma.Args[name]; ok { return arg.Value } } return "" } // Of the form: `const x = require("x")` or `const { x } = require("x")` or with `var` or `let` // The variable must not be exported and must not have a type annotation, even a jsdoc one. // The initializer must be a call to `require` with a string literal or a string literal-like argument. func IsVariableDeclarationInitializedToRequire(node *Node) bool { if !IsInJSFile(node) { return false } if node.Kind == KindBindingElement { node = node.Parent.Parent } if node.Kind != KindVariableDeclaration { return false } return node.Parent.Parent.ModifierFlags()&ModifierFlagsExport == 0 && node.AsVariableDeclaration().Initializer != nil && node.Type() == nil && IsRequireCall(node.AsVariableDeclaration().Initializer, true /*requireStringLiteralLikeArgument*/) } func IsModuleExportsAccessExpression(node *Node) bool { if IsAccessExpression(node) && IsModuleIdentifier(node.Expression()) { if name := GetElementOrPropertyAccessName(node); name != nil { return name.Text() == "exports" } } return false } func IsCheckJSEnabledForFile(sourceFile *SourceFile, compilerOptions *core.CompilerOptions) bool { if sourceFile.CheckJsDirective != nil { return sourceFile.CheckJsDirective.Enabled } return compilerOptions.CheckJs == core.TSTrue } func IsPlainJSFile(file *SourceFile, checkJs core.Tristate) bool { return file != nil && (file.ScriptKind == core.ScriptKindJS || file.ScriptKind == core.ScriptKindJSX) && file.CheckJsDirective == nil && checkJs == core.TSUnknown } func GetLeftmostAccessExpression(expr *Node) *Node { for IsAccessExpression(expr) { expr = expr.Expression() } return expr } func IsTypeOnlyImportDeclaration(node *Node) bool { switch node.Kind { case KindImportSpecifier: return node.IsTypeOnly() || node.Parent.Parent.IsTypeOnly() case KindNamespaceImport: return node.Parent.IsTypeOnly() case KindImportClause, KindImportEqualsDeclaration: return node.IsTypeOnly() } return false } func isTypeOnlyExportDeclaration(node *Node) bool { switch node.Kind { case KindExportSpecifier: return node.AsExportSpecifier().IsTypeOnly || node.Parent.Parent.AsExportDeclaration().IsTypeOnly case KindExportDeclaration: d := node.AsExportDeclaration() return d.IsTypeOnly && d.ModuleSpecifier != nil && d.ExportClause == nil case KindNamespaceExport: return node.Parent.AsExportDeclaration().IsTypeOnly } return false } func IsTypeOnlyImportOrExportDeclaration(node *Node) bool { return IsTypeOnlyImportDeclaration(node) || isTypeOnlyExportDeclaration(node) } func IsExclusivelyTypeOnlyImportOrExport(node *Node) bool { switch node.Kind { case KindExportDeclaration: return node.AsExportDeclaration().IsTypeOnly case KindImportDeclaration, KindJSImportDeclaration: if importClause := node.AsImportDeclaration().ImportClause; importClause != nil { return importClause.AsImportClause().IsTypeOnly() } case KindJSDocImportTag: if importClause := node.AsJSDocImportTag().ImportClause; importClause != nil { return importClause.AsImportClause().IsTypeOnly() } } return false } func GetClassLikeDeclarationOfSymbol(symbol *Symbol) *Node { return core.Find(symbol.Declarations, IsClassLike) } func IsCallLikeExpression(node *Node) bool { switch node.Kind { case KindJsxOpeningElement, KindJsxSelfClosingElement, KindJsxOpeningFragment, KindCallExpression, KindNewExpression, KindTaggedTemplateExpression, KindDecorator: return true case KindBinaryExpression: return node.AsBinaryExpression().OperatorToken.Kind == KindInstanceOfKeyword } return false } func IsJsxCallLike(node *Node) bool { switch node.Kind { case KindJsxOpeningElement, KindJsxSelfClosingElement, KindJsxOpeningFragment: return true } return false } func IsCallLikeOrFunctionLikeExpression(node *Node) bool { return IsCallLikeExpression(node) || IsFunctionExpressionOrArrowFunction(node) } func NodeHasKind(node *Node, kind Kind) bool { if node == nil { return false } return node.Kind == kind } func IsContextualKeyword(token Kind) bool { return KindFirstContextualKeyword <= token && token <= KindLastContextualKeyword } func IsThisInTypeQuery(node *Node) bool { if !IsThisIdentifier(node) { return false } for IsQualifiedName(node.Parent) && node.Parent.AsQualifiedName().Left == node { node = node.Parent } return node.Parent.Kind == KindTypeQuery } // Gets whether a bound `VariableDeclaration` or `VariableDeclarationList` is part of a `let` declaration. func IsLet(node *Node) bool { return GetCombinedNodeFlags(node)&NodeFlagsBlockScoped == NodeFlagsLet } func IsClassMemberModifier(token Kind) bool { return IsParameterPropertyModifier(token) || token == KindStaticKeyword || token == KindOverrideKeyword || token == KindAccessorKeyword } func IsParameterPropertyModifier(kind Kind) bool { return ModifierToFlag(kind)&ModifierFlagsParameterPropertyModifier != 0 } func ForEachChildAndJSDoc(node *Node, sourceFile *SourceFile, v Visitor) bool { if node.Flags&NodeFlagsHasJSDoc != 0 { if visitNodes(v, node.JSDoc(sourceFile)) { return true } } return node.ForEachChild(v) } func IsTypeReferenceType(node *Node) bool { return node.Kind == KindTypeReference || node.Kind == KindExpressionWithTypeArguments } func IsVariableLike(node *Node) bool { switch node.Kind { case KindBindingElement, KindEnumMember, KindParameter, KindPropertyAssignment, KindPropertyDeclaration, KindPropertySignature, KindShorthandPropertyAssignment, KindVariableDeclaration: return true } return false } func HasInitializer(node *Node) bool { switch node.Kind { case KindVariableDeclaration, KindParameter, KindBindingElement, KindPropertyDeclaration, KindPropertyAssignment, KindEnumMember, KindForStatement, KindForInStatement, KindForOfStatement, KindJsxAttribute: return node.Initializer() != nil default: return false } } func GetTypeAnnotationNode(node *Node) *TypeNode { switch node.Kind { case KindVariableDeclaration, KindParameter, KindPropertySignature, KindPropertyDeclaration, KindTypePredicate, KindParenthesizedType, KindTypeOperator, KindMappedType, KindTypeAssertionExpression, KindAsExpression, KindSatisfiesExpression, KindTypeAliasDeclaration, KindJSTypeAliasDeclaration, KindNamedTupleMember, KindOptionalType, KindRestType, KindTemplateLiteralTypeSpan, KindJSDocTypeExpression, KindJSDocPropertyTag, KindJSDocNullableType, KindJSDocNonNullableType, KindJSDocOptionalType: return node.Type() default: funcLike := node.FunctionLikeData() if funcLike != nil { return funcLike.Type } return nil } } func IsObjectTypeDeclaration(node *Node) bool { return IsClassLike(node) || IsInterfaceDeclaration(node) || IsTypeLiteralNode(node) } func IsClassOrTypeElement(node *Node) bool { return IsClassElement(node) || IsTypeElement(node) } func GetClassExtendsHeritageElement(node *Node) *ExpressionWithTypeArgumentsNode { heritageElements := GetHeritageElements(node, KindExtendsKeyword) if len(heritageElements) > 0 { return heritageElements[0] } return nil } func GetImplementsTypeNodes(node *Node) []*ExpressionWithTypeArgumentsNode { return GetHeritageElements(node, KindImplementsKeyword) } func IsTypeKeywordToken(node *Node) bool { return node.Kind == KindTypeKeyword } // See `IsJSDocSingleCommentNode`. func IsJSDocSingleCommentNodeList(nodeList *NodeList) bool { if nodeList == nil || len(nodeList.Nodes) == 0 { return false } parent := nodeList.Nodes[0].Parent return IsJSDocSingleCommentNode(parent) && nodeList == parent.CommentList() } // See `IsJSDocSingleCommentNode`. func IsJSDocSingleCommentNodeComment(node *Node) bool { if node == nil || node.Parent == nil { return false } return IsJSDocSingleCommentNode(node.Parent) && node == node.Parent.CommentList().Nodes[0] } // In Strada, if a JSDoc node has a single comment, that comment is represented as a string property // as a simplification, and therefore that comment is not visited by `forEachChild`. func IsJSDocSingleCommentNode(node *Node) bool { return hasComment(node.Kind) && node.CommentList() != nil && len(node.CommentList().Nodes) == 1 } func IsValidTypeOnlyAliasUseSite(useSite *Node) bool { return useSite.Flags&(NodeFlagsAmbient|NodeFlagsJSDoc) != 0 || IsPartOfTypeQuery(useSite) || isIdentifierInNonEmittingHeritageClause(useSite) || isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(useSite) || !(IsExpressionNode(useSite) || isShorthandPropertyNameUseSite(useSite)) } func isIdentifierInNonEmittingHeritageClause(node *Node) bool { if !IsIdentifier(node) { return false } parent := node.Parent for IsPropertyAccessExpression(parent) || IsExpressionWithTypeArguments(parent) { parent = parent.Parent } return IsHeritageClause(parent) && (parent.AsHeritageClause().Token == KindImplementsKeyword || IsInterfaceDeclaration(parent.Parent)) } func isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(node *Node) bool { for NodeKindIs(node, KindIdentifier, KindPropertyAccessExpression) { node = node.Parent } if node.Kind != KindComputedPropertyName { return false } if HasSyntacticModifier(node.Parent, ModifierFlagsAbstract) { return true } return NodeKindIs(node.Parent.Parent, KindInterfaceDeclaration, KindTypeLiteral) } func isShorthandPropertyNameUseSite(useSite *Node) bool { return IsIdentifier(useSite) && IsShorthandPropertyAssignment(useSite.Parent) && useSite.Parent.AsShorthandPropertyAssignment().Name() == useSite } func GetPropertyNameForPropertyNameNode(name *Node) string { switch name.Kind { case KindIdentifier, KindPrivateIdentifier, KindStringLiteral, KindNoSubstitutionTemplateLiteral, KindNumericLiteral, KindBigIntLiteral, KindJsxNamespacedName: return name.Text() case KindComputedPropertyName: nameExpression := name.AsComputedPropertyName().Expression if IsStringOrNumericLiteralLike(nameExpression) { return nameExpression.Text() } if IsSignedNumericLiteral(nameExpression) { text := nameExpression.AsPrefixUnaryExpression().Operand.Text() if nameExpression.AsPrefixUnaryExpression().Operator == KindMinusToken { text = "-" + text } return text } return InternalSymbolNameMissing } panic("Unhandled case in getPropertyNameForPropertyNameNode") } func IsPartOfTypeOnlyImportOrExportDeclaration(node *Node) bool { return FindAncestor(node, IsTypeOnlyImportOrExportDeclaration) != nil } func IsPartOfExclusivelyTypeOnlyImportOrExportDeclaration(node *Node) bool { return FindAncestor(node, IsExclusivelyTypeOnlyImportOrExport) != nil } func IsEmittableImport(node *Node) bool { switch node.Kind { case KindImportDeclaration: return node.AsImportDeclaration().ImportClause != nil && !node.AsImportDeclaration().ImportClause.IsTypeOnly() case KindExportDeclaration: return !node.AsExportDeclaration().IsTypeOnly case KindImportEqualsDeclaration: return !node.AsImportEqualsDeclaration().IsTypeOnly case KindCallExpression: return IsImportCall(node) } return false } func IsResolutionModeOverrideHost(node *Node) bool { if node == nil { return false } switch node.Kind { case KindImportType, KindExportDeclaration, KindImportDeclaration, KindJSImportDeclaration: return true } return false } func HasResolutionModeOverride(node *Node) bool { if node == nil { return false } var attributes *ImportAttributesNode switch node.Kind { case KindImportType: attributes = node.AsImportTypeNode().Attributes case KindImportDeclaration, KindJSImportDeclaration: attributes = node.AsImportDeclaration().Attributes case KindExportDeclaration: attributes = node.AsExportDeclaration().Attributes } if attributes != nil { _, ok := attributes.GetResolutionModeOverride() return ok } return false } func IsStringTextContainingNode(node *Node) bool { return node.Kind == KindStringLiteral || IsTemplateLiteralKind(node.Kind) } func IsTemplateLiteralKind(kind Kind) bool { return KindFirstTemplateToken <= kind && kind <= KindLastTemplateToken } func IsTemplateLiteralToken(node *Node) bool { return IsTemplateLiteralKind(node.Kind) } func GetExternalModuleImportEqualsDeclarationExpression(node *Node) *Node { debug.Assert(IsExternalModuleImportEqualsDeclaration(node)) return node.AsImportEqualsDeclaration().ModuleReference.AsExternalModuleReference().Expression } func CreateModifiersFromModifierFlags(flags ModifierFlags, createModifier func(kind Kind) *Node) []*Node { var result []*Node if flags&ModifierFlagsExport != 0 { result = append(result, createModifier(KindExportKeyword)) } if flags&ModifierFlagsAmbient != 0 { result = append(result, createModifier(KindDeclareKeyword)) } if flags&ModifierFlagsDefault != 0 { result = append(result, createModifier(KindDefaultKeyword)) } if flags&ModifierFlagsConst != 0 { result = append(result, createModifier(KindConstKeyword)) } if flags&ModifierFlagsPublic != 0 { result = append(result, createModifier(KindPublicKeyword)) } if flags&ModifierFlagsPrivate != 0 { result = append(result, createModifier(KindPrivateKeyword)) } if flags&ModifierFlagsProtected != 0 { result = append(result, createModifier(KindProtectedKeyword)) } if flags&ModifierFlagsAbstract != 0 { result = append(result, createModifier(KindAbstractKeyword)) } if flags&ModifierFlagsStatic != 0 { result = append(result, createModifier(KindStaticKeyword)) } if flags&ModifierFlagsOverride != 0 { result = append(result, createModifier(KindOverrideKeyword)) } if flags&ModifierFlagsReadonly != 0 { result = append(result, createModifier(KindReadonlyKeyword)) } if flags&ModifierFlagsAccessor != 0 { result = append(result, createModifier(KindAccessorKeyword)) } if flags&ModifierFlagsAsync != 0 { result = append(result, createModifier(KindAsyncKeyword)) } if flags&ModifierFlagsIn != 0 { result = append(result, createModifier(KindInKeyword)) } if flags&ModifierFlagsOut != 0 { result = append(result, createModifier(KindOutKeyword)) } return result } func GetThisParameter(signature *Node) *Node { // callback tags do not currently support this parameters if len(signature.Parameters()) != 0 { thisParameter := signature.Parameters()[0] if IsThisParameter(thisParameter) { return thisParameter } } return nil } func ReplaceModifiers(factory *NodeFactory, node *Node, modifierArray *ModifierList) *Node { switch node.Kind { case KindTypeParameter: return factory.UpdateTypeParameterDeclaration( node.AsTypeParameter(), modifierArray, node.Name(), node.AsTypeParameter().Constraint, node.AsTypeParameter().DefaultType, ) case KindParameter: return factory.UpdateParameterDeclaration( node.AsParameterDeclaration(), modifierArray, node.AsParameterDeclaration().DotDotDotToken, node.Name(), node.AsParameterDeclaration().QuestionToken, node.Type(), node.Initializer(), ) case KindConstructorType: return factory.UpdateConstructorTypeNode( node.AsConstructorTypeNode(), modifierArray, node.TypeParameterList(), node.ParameterList(), node.Type(), ) case KindPropertySignature: return factory.UpdatePropertySignatureDeclaration( node.AsPropertySignatureDeclaration(), modifierArray, node.Name(), node.AsPropertySignatureDeclaration().PostfixToken, node.Type(), node.Initializer(), ) case KindPropertyDeclaration: return factory.UpdatePropertyDeclaration( node.AsPropertyDeclaration(), modifierArray, node.Name(), node.AsPropertyDeclaration().PostfixToken, node.Type(), node.Initializer(), ) case KindMethodSignature: return factory.UpdateMethodSignatureDeclaration( node.AsMethodSignatureDeclaration(), modifierArray, node.Name(), node.AsMethodSignatureDeclaration().PostfixToken, node.TypeParameterList(), node.ParameterList(), node.Type(), ) case KindMethodDeclaration: return factory.UpdateMethodDeclaration( node.AsMethodDeclaration(), modifierArray, node.AsMethodDeclaration().AsteriskToken, node.Name(), node.AsMethodDeclaration().PostfixToken, node.TypeParameterList(), node.ParameterList(), node.Type(), node.AsMethodDeclaration().FullSignature, node.Body(), ) case KindConstructor: return factory.UpdateConstructorDeclaration( node.AsConstructorDeclaration(), modifierArray, node.TypeParameterList(), node.ParameterList(), node.Type(), node.AsConstructorDeclaration().FullSignature, node.Body(), ) case KindGetAccessor: return factory.UpdateGetAccessorDeclaration( node.AsGetAccessorDeclaration(), modifierArray, node.Name(), node.TypeParameterList(), node.ParameterList(), node.Type(), node.AsGetAccessorDeclaration().FullSignature, node.Body(), ) case KindSetAccessor: return factory.UpdateSetAccessorDeclaration( node.AsSetAccessorDeclaration(), modifierArray, node.Name(), node.TypeParameterList(), node.ParameterList(), node.Type(), node.AsSetAccessorDeclaration().FullSignature, node.Body(), ) case KindIndexSignature: return factory.UpdateIndexSignatureDeclaration( node.AsIndexSignatureDeclaration(), modifierArray, node.ParameterList(), node.Type(), ) case KindFunctionExpression: return factory.UpdateFunctionExpression( node.AsFunctionExpression(), modifierArray, node.AsFunctionExpression().AsteriskToken, node.Name(), node.TypeParameterList(), node.ParameterList(), node.Type(), node.AsFunctionExpression().FullSignature, node.Body(), ) case KindArrowFunction: return factory.UpdateArrowFunction( node.AsArrowFunction(), modifierArray, node.TypeParameterList(), node.ParameterList(), node.Type(), node.AsArrowFunction().FullSignature, node.AsArrowFunction().EqualsGreaterThanToken, node.Body(), ) case KindClassExpression: return factory.UpdateClassExpression( node.AsClassExpression(), modifierArray, node.Name(), node.TypeParameterList(), node.AsClassExpression().HeritageClauses, node.MemberList(), ) case KindVariableStatement: return factory.UpdateVariableStatement( node.AsVariableStatement(), modifierArray, node.AsVariableStatement().DeclarationList, ) case KindFunctionDeclaration: return factory.UpdateFunctionDeclaration( node.AsFunctionDeclaration(), modifierArray, node.AsFunctionDeclaration().AsteriskToken, node.Name(), node.TypeParameterList(), node.ParameterList(), node.Type(), node.AsFunctionDeclaration().FullSignature, node.Body(), ) case KindClassDeclaration: return factory.UpdateClassDeclaration( node.AsClassDeclaration(), modifierArray, node.Name(), node.TypeParameterList(), node.AsClassDeclaration().HeritageClauses, node.MemberList(), ) case KindInterfaceDeclaration: return factory.UpdateInterfaceDeclaration( node.AsInterfaceDeclaration(), modifierArray, node.Name(), node.TypeParameterList(), node.AsInterfaceDeclaration().HeritageClauses, node.MemberList(), ) case KindTypeAliasDeclaration: return factory.UpdateTypeAliasDeclaration( node.AsTypeAliasDeclaration(), modifierArray, node.Name(), node.TypeParameterList(), node.Type(), ) case KindEnumDeclaration: return factory.UpdateEnumDeclaration( node.AsEnumDeclaration(), modifierArray, node.Name(), node.MemberList(), ) case KindModuleDeclaration: return factory.UpdateModuleDeclaration( node.AsModuleDeclaration(), modifierArray, node.AsModuleDeclaration().Keyword, node.Name(), node.Body(), ) case KindImportEqualsDeclaration: return factory.UpdateImportEqualsDeclaration( node.AsImportEqualsDeclaration(), modifierArray, node.IsTypeOnly(), node.Name(), node.AsImportEqualsDeclaration().ModuleReference, ) case KindImportDeclaration: return factory.UpdateImportDeclaration( node.AsImportDeclaration(), modifierArray, node.AsImportDeclaration().ImportClause, node.AsImportDeclaration().ModuleSpecifier, node.AsImportDeclaration().Attributes, ) case KindExportAssignment: return factory.UpdateExportAssignment( node.AsExportAssignment(), modifierArray, node.Type(), node.Expression(), ) case KindExportDeclaration: return factory.UpdateExportDeclaration( node.AsExportDeclaration(), modifierArray, node.IsTypeOnly(), node.AsExportDeclaration().ExportClause, node.AsExportDeclaration().ModuleSpecifier, node.AsExportDeclaration().Attributes, ) } panic(fmt.Sprintf("Node that does not have modifiers tried to have modifier replaced: %d", node.Kind)) } func IsLateVisibilityPaintedStatement(node *Node) bool { switch node.Kind { case KindImportDeclaration, KindJSImportDeclaration, KindImportEqualsDeclaration, KindVariableStatement, KindClassDeclaration, KindFunctionDeclaration, KindModuleDeclaration, KindTypeAliasDeclaration, KindJSTypeAliasDeclaration, KindInterfaceDeclaration, KindEnumDeclaration: return true default: return false } } func IsExternalModuleAugmentation(node *Node) bool { return IsAmbientModule(node) && IsModuleAugmentationExternal(node) } func GetSourceFileOfModule(module *Symbol) *SourceFile { declaration := module.ValueDeclaration if declaration == nil { declaration = getNonAugmentationDeclaration(module) } return GetSourceFileOfNode(declaration) } func getNonAugmentationDeclaration(symbol *Symbol) *Node { return core.Find(symbol.Declarations, func(d *Node) bool { return !IsExternalModuleAugmentation(d) && !IsGlobalScopeAugmentation(d) }) } func IsTypeDeclaration(node *Node) bool { switch node.Kind { case KindTypeParameter, KindClassDeclaration, KindInterfaceDeclaration, KindTypeAliasDeclaration, KindJSTypeAliasDeclaration, KindEnumDeclaration: return true case KindImportClause: return node.AsImportClause().PhaseModifier == KindTypeKeyword case KindImportSpecifier: return node.Parent.Parent.AsImportClause().PhaseModifier == KindTypeKeyword case KindExportSpecifier: return node.Parent.Parent.AsExportDeclaration().IsTypeOnly default: return false } } func IsTypeDeclarationName(name *Node) bool { return name.Kind == KindIdentifier && IsTypeDeclaration(name.Parent) && GetNameOfDeclaration(name.Parent) == name } func IsRightSideOfQualifiedNameOrPropertyAccess(node *Node) bool { parent := node.Parent switch parent.Kind { case KindQualifiedName: return parent.AsQualifiedName().Right == node case KindPropertyAccessExpression: return parent.AsPropertyAccessExpression().Name() == node case KindMetaProperty: return parent.AsMetaProperty().Name() == node } return false } func ShouldTransformImportCall(fileName string, options *core.CompilerOptions, impliedNodeFormatForEmit core.ModuleKind) bool { moduleKind := options.GetEmitModuleKind() if core.ModuleKindNode16 <= moduleKind && moduleKind <= core.ModuleKindNodeNext || moduleKind == core.ModuleKindPreserve { return false } return impliedNodeFormatForEmit < core.ModuleKindES2015 } func HasQuestionToken(node *Node) bool { return IsQuestionToken(node.PostfixToken()) } func IsJsxOpeningLikeElement(node *Node) bool { return IsJsxOpeningElement(node) || IsJsxSelfClosingElement(node) } func GetInvokedExpression(node *Node) *Node { switch node.Kind { case KindTaggedTemplateExpression: return node.AsTaggedTemplateExpression().Tag case KindJsxOpeningElement, KindJsxSelfClosingElement: return node.TagName() case KindBinaryExpression: return node.AsBinaryExpression().Right case KindJsxOpeningFragment: return node default: return node.Expression() } } func IsCallOrNewExpression(node *Node) bool { return IsCallExpression(node) || IsNewExpression(node) } func IndexOfNode(nodes []*Node, node *Node) int { index, ok := slices.BinarySearchFunc(nodes, node, compareNodePositions) if ok { return index } return -1 } func compareNodePositions(n1, n2 *Node) int { return n1.Pos() - n2.Pos() } func IsUnterminatedLiteral(node *Node) bool { return IsLiteralKind(node.Kind) && node.LiteralLikeData().TokenFlags&TokenFlagsUnterminated != 0 || IsTemplateLiteralKind(node.Kind) && node.TemplateLiteralLikeData().TemplateFlags&TokenFlagsUnterminated != 0 } // Gets a value indicating whether a class element is either a static or an instance property declaration with an initializer. func IsInitializedProperty(member *ClassElement) bool { return member.Kind == KindPropertyDeclaration && member.Initializer() != nil } func IsTrivia(token Kind) bool { return KindFirstTriviaToken <= token && token <= KindLastTriviaToken } func HasDecorators(node *Node) bool { return HasSyntacticModifier(node, ModifierFlagsDecorator) } type hasFileNameImpl struct { fileName string path tspath.Path } func NewHasFileName(fileName string, path tspath.Path) HasFileName { return &hasFileNameImpl{ fileName: fileName, path: path, } } func (h *hasFileNameImpl) FileName() string { return h.fileName } func (h *hasFileNameImpl) Path() tspath.Path { return h.path } func GetSemanticJsxChildren(children []*JsxChild) []*JsxChild { return core.Filter(children, func(i *JsxChild) bool { switch i.Kind { case KindJsxExpression: return i.Expression() != nil case KindJsxText: return !i.AsJsxText().ContainsOnlyTriviaWhiteSpaces default: return true } }) } // Returns true if the node kind has a comment property. func hasComment(kind Kind) bool { switch kind { case KindJSDoc, KindJSDocTag, KindJSDocAugmentsTag, KindJSDocImplementsTag, KindJSDocDeprecatedTag, KindJSDocPublicTag, KindJSDocPrivateTag, KindJSDocProtectedTag, KindJSDocReadonlyTag, KindJSDocOverrideTag, KindJSDocCallbackTag, KindJSDocOverloadTag, KindJSDocParameterTag, KindJSDocPropertyTag, KindJSDocReturnTag, KindJSDocThisTag, KindJSDocTypeTag, KindJSDocTemplateTag, KindJSDocTypedefTag, KindJSDocSeeTag, KindJSDocSatisfiesTag, KindJSDocImportTag: return true default: return false } } func IsAssignmentPattern(node *Node) bool { return node.Kind == KindArrayLiteralExpression || node.Kind == KindObjectLiteralExpression } func GetElementsOfBindingOrAssignmentPattern(name *Node) []*Node { switch name.Kind { case KindObjectBindingPattern, KindArrayBindingPattern: // `a` in `{a}` // `a` in `[a]` return name.AsBindingPattern().Elements.Nodes case KindArrayLiteralExpression: // `a` in `[a]` return name.AsArrayLiteralExpression().Elements.Nodes case KindObjectLiteralExpression: // `a` in `{a}` return name.AsObjectLiteralExpression().Properties.Nodes } return nil } func IsDeclarationBindingElement(bindingElement *Node) bool { switch bindingElement.Kind { case KindVariableDeclaration, KindParameter, KindBindingElement: return true default: return false } } /** * Gets the name of an BindingOrAssignmentElement. */ func GetTargetOfBindingOrAssignmentElement(bindingElement *Node) *Node { if IsDeclarationBindingElement(bindingElement) { // `a` in `let { a } = ...` // `a` in `let { a = 1 } = ...` // `b` in `let { a: b } = ...` // `b` in `let { a: b = 1 } = ...` // `a` in `let { ...a } = ...` // `{b}` in `let { a: {b} } = ...` // `{b}` in `let { a: {b} = 1 } = ...` // `[b]` in `let { a: [b] } = ...` // `[b]` in `let { a: [b] = 1 } = ...` // `a` in `let [a] = ...` // `a` in `let [a = 1] = ...` // `a` in `let [...a] = ...` // `{a}` in `let [{a}] = ...` // `{a}` in `let [{a} = 1] = ...` // `[a]` in `let [[a]] = ...` // `[a]` in `let [[a] = 1] = ...` return bindingElement.Name() } if IsObjectLiteralElement(bindingElement) { switch bindingElement.Kind { case KindPropertyAssignment: // `b` in `({ a: b } = ...)` // `b` in `({ a: b = 1 } = ...)` // `{b}` in `({ a: {b} } = ...)` // `{b}` in `({ a: {b} = 1 } = ...)` // `[b]` in `({ a: [b] } = ...)` // `[b]` in `({ a: [b] = 1 } = ...)` // `b.c` in `({ a: b.c } = ...)` // `b.c` in `({ a: b.c = 1 } = ...)` // `b[0]` in `({ a: b[0] } = ...)` // `b[0]` in `({ a: b[0] = 1 } = ...)` return GetTargetOfBindingOrAssignmentElement(bindingElement.Initializer()) case KindShorthandPropertyAssignment: // `a` in `({ a } = ...)` // `a` in `({ a = 1 } = ...)` return bindingElement.Name() case KindSpreadAssignment: // `a` in `({ ...a } = ...)` return GetTargetOfBindingOrAssignmentElement(bindingElement.AsSpreadAssignment().Expression) } // no target return nil } if IsAssignmentExpression(bindingElement /*excludeCompoundAssignment*/, true) { // `a` in `[a = 1] = ...` // `{a}` in `[{a} = 1] = ...` // `[a]` in `[[a] = 1] = ...` // `a.b` in `[a.b = 1] = ...` // `a[0]` in `[a[0] = 1] = ...` return GetTargetOfBindingOrAssignmentElement(bindingElement.AsBinaryExpression().Left) } if IsSpreadElement(bindingElement) { // `a` in `[...a] = ...` return GetTargetOfBindingOrAssignmentElement(bindingElement.AsSpreadElement().Expression) } // `a` in `[a] = ...` // `{a}` in `[{a}] = ...` // `[a]` in `[[a]] = ...` // `a.b` in `[a.b] = ...` // `a[0]` in `[a[0]] = ...` return bindingElement } func TryGetPropertyNameOfBindingOrAssignmentElement(bindingElement *Node) *Node { switch bindingElement.Kind { case KindBindingElement: // `a` in `let { a: b } = ...` // `[a]` in `let { [a]: b } = ...` // `"a"` in `let { "a": b } = ...` // `1` in `let { 1: b } = ...` if bindingElement.AsBindingElement().PropertyName != nil { propertyName := bindingElement.AsBindingElement().PropertyName // if ast.IsPrivateIdentifier(propertyName) { // return Debug.failBadSyntaxKind(propertyName) // !!! // } if IsComputedPropertyName(propertyName) && IsStringOrNumericLiteralLike(propertyName.AsComputedPropertyName().Expression) { return propertyName.AsComputedPropertyName().Expression } return propertyName } case KindPropertyAssignment: // `a` in `({ a: b } = ...)` // `[a]` in `({ [a]: b } = ...)` // `"a"` in `({ "a": b } = ...)` // `1` in `({ 1: b } = ...)` if bindingElement.Name() != nil { propertyName := bindingElement.Name() // if ast.IsPrivateIdentifier(propertyName) { // return Debug.failBadSyntaxKind(propertyName) // !!! // } if IsComputedPropertyName(propertyName) && IsStringOrNumericLiteralLike(propertyName.AsComputedPropertyName().Expression) { return propertyName.AsComputedPropertyName().Expression } return propertyName } case KindSpreadAssignment: // `a` in `({ ...a } = ...)` // if ast.IsPrivateIdentifier(bindingElement.Name()) { // return Debug.failBadSyntaxKind(bindingElement.Name()) // !!! // } return bindingElement.Name() } target := GetTargetOfBindingOrAssignmentElement(bindingElement) if target != nil && IsPropertyName(target) { return target } return nil } /** * Walk an AssignmentPattern to determine if it contains object rest (`...`) syntax. We cannot rely on * propagation of `TransformFlags.ContainsObjectRestOrSpread` since it isn't propagated by default in * ObjectLiteralExpression and ArrayLiteralExpression since we do not know whether they belong to an * AssignmentPattern at the time the nodes are parsed. */ func ContainsObjectRestOrSpread(node *Node) bool { if node.SubtreeFacts()&SubtreeContainsObjectRestOrSpread != 0 { return true } if node.SubtreeFacts()&SubtreeContainsESObjectRestOrSpread != 0 { // check for nested spread assignments, otherwise '{ x: { a, ...b } = foo } = c' // will not be correctly interpreted by the rest/spread transformer for _, element := range GetElementsOfBindingOrAssignmentPattern(node) { target := GetTargetOfBindingOrAssignmentElement(element) if target != nil && IsAssignmentPattern(target) { if target.SubtreeFacts()&SubtreeContainsObjectRestOrSpread != 0 { return true } if target.SubtreeFacts()&SubtreeContainsESObjectRestOrSpread != 0 { if ContainsObjectRestOrSpread(target) { return true } } } } } return false } func IsEmptyObjectLiteral(expression *Node) bool { return expression.Kind == KindObjectLiteralExpression && len(expression.AsObjectLiteralExpression().Properties.Nodes) == 0 } func IsEmptyArrayLiteral(expression *Node) bool { return expression.Kind == KindArrayLiteralExpression && len(expression.AsArrayLiteralExpression().Elements.Nodes) == 0 } func GetRestIndicatorOfBindingOrAssignmentElement(bindingElement *Node) *Node { switch bindingElement.Kind { case KindParameter: return bindingElement.AsParameterDeclaration().DotDotDotToken case KindBindingElement: return bindingElement.AsBindingElement().DotDotDotToken case KindSpreadElement, KindSpreadAssignment: return bindingElement } return nil } func IsJSDocNameReferenceContext(node *Node) bool { return node.Flags&NodeFlagsJSDoc != 0 && FindAncestor(node, func(node *Node) bool { return IsJSDocNameReference(node) || IsJSDocLinkLike(node) }) != nil } func IsImportOrImportEqualsDeclaration(node *Node) bool { return IsImportDeclaration(node) || IsImportEqualsDeclaration(node) } func IsKeyword(token Kind) bool { return KindFirstKeyword <= token && token <= KindLastKeyword } func IsNonContextualKeyword(token Kind) bool { return IsKeyword(token) && !IsContextualKeyword(token) } func HasModifier(node *Node, flags ModifierFlags) bool { return node.ModifierFlags()&flags != 0 } func IsExpandoInitializer(initializer *Node) bool { if initializer == nil { return false } if IsFunctionExpressionOrArrowFunction(initializer) { return true } if IsInJSFile(initializer) { return IsClassExpression(initializer) || (IsObjectLiteralExpression(initializer) && len(initializer.AsObjectLiteralExpression().Properties.Nodes) == 0) } return false } func GetContainingFunction(node *Node) *Node { return FindAncestor(node.Parent, IsFunctionLike) }