diff --git a/cmd/tsgo/main.go b/cmd/tsgo/main.go
index 5f5318b0cc..118ba19ea3 100644
--- a/cmd/tsgo/main.go
+++ b/cmd/tsgo/main.go
@@ -2,9 +2,60 @@
package main
import (
- "github.com/microsoft/typescript-go/internal/compiler"
+ "flag"
+ "fmt"
+ "runtime"
+ "strings"
+ "time"
+
+ ts "github.com/microsoft/typescript-go/internal/compiler"
)
+var quiet = false
+var singleThreaded = false
+var parseAndBindOnly = false
+
+func printDiagnostic(d *ts.Diagnostic, level int) {
+ file := d.File()
+ if file != nil {
+ line, character := ts.GetLineAndCharacterOfPosition(file, d.Loc().Pos())
+ fmt.Printf("%v%v(%v,%v): error TS%v: %v\n", strings.Repeat(" ", level*2), file.FileName(), line+1, character+1, d.Code(), d.Message())
+ } else {
+ fmt.Printf("%verror TS%v: %v\n", strings.Repeat(" ", level*2), d.Code(), d.Message())
+ }
+ for _, r := range d.RelatedInformation() {
+ printDiagnostic(r, level+1)
+ }
+}
+
func main() {
- compiler.CreateSourceFile()
+ flag.BoolVar(&quiet, "q", false, "Quiet output")
+ flag.BoolVar(&singleThreaded, "s", false, "Single threaded")
+ flag.BoolVar(&parseAndBindOnly, "p", false, "Parse and bind only")
+ flag.Parse()
+ compilerOptions := &ts.CompilerOptions{Target: ts.ScriptTargetESNext, ModuleKind: ts.ModuleKindNodeNext}
+ programOptions := ts.ProgramOptions{RootPath: flag.Arg(0), Options: compilerOptions, SingleThreaded: singleThreaded}
+ startTime := time.Now()
+ program := ts.NewProgram(programOptions)
+ diagnostics := program.GetSyntacticDiagnostics(nil)
+ if len(diagnostics) == 0 {
+ if parseAndBindOnly {
+ diagnostics = program.GetBindDiagnostics(nil)
+ } else {
+ diagnostics = program.GetSemanticDiagnostics(nil)
+ }
+ }
+ compileTime := time.Since(startTime)
+ var memStats runtime.MemStats
+ runtime.GC()
+ runtime.GC()
+ runtime.ReadMemStats(&memStats)
+ if !quiet {
+ for _, diagnostic := range diagnostics {
+ printDiagnostic(diagnostic, 0)
+ }
+ }
+ fmt.Printf("Files: %v\n", len(program.SourceFiles()))
+ fmt.Printf("Compile time: %v\n", compileTime)
+ fmt.Printf("Memory used: %vK\n", memStats.Alloc/1024)
}
diff --git a/internal/compiler/ast.go b/internal/compiler/ast.go
new file mode 100644
index 0000000000..12e22b8503
--- /dev/null
+++ b/internal/compiler/ast.go
@@ -0,0 +1,4126 @@
+package compiler
+
+import "reflect"
+
+// Visitor
+
+type Visitor func(*Node) bool
+
+func visit(v Visitor, node *Node) bool {
+ if node != nil {
+ return v(node)
+ }
+ return false
+}
+
+func visitNodes(v Visitor, nodes []*Node) bool {
+ for _, node := range nodes {
+ if v(node) {
+ return true
+ }
+ }
+ return false
+}
+
+// In situations where conversions from a pointer type may produce a typed nil, this function can be used
+// to check that the interface truly references an existing struct.
+func exists(i interface{}) bool {
+ return !(i == nil || reflect.ValueOf(i).IsNil())
+}
+
+// NodeFactory
+
+type NodeFactory struct {
+ identifierPool Pool[Identifier]
+}
+
+func (f *NodeFactory) NewNode(kind SyntaxKind, data NodeData) *Node {
+ n := data.AsNode()
+ n.kind = kind
+ n.data = data
+ return n
+}
+
+// AST Node
+// Interface values stored in AST nodes are never typed nil values. Construction code must ensure that
+// interface valued properties either store a true nil or a reference to a non-nil struct.
+
+type Node struct {
+ kind SyntaxKind
+ flags NodeFlags
+ loc TextRange
+ id NodeId
+ parent *Node
+ data NodeData
+}
+
+// Node accessors
+
+func (n *Node) Pos() int { return n.loc.Pos() }
+func (n *Node) End() int { return n.loc.End() }
+func (n *Node) ForEachChild(v Visitor) bool { return n.data.ForEachChild(v) }
+func (n *Node) Symbol() *Symbol { return n.data.Symbol() }
+func (n *Node) LocalSymbol() *Symbol { return n.data.LocalSymbol() }
+func (n *Node) Modifiers() *ModifierListNode { return n.data.Modifiers() }
+func (n *Node) Name() *DeclarationName { return n.data.Name() }
+func (n *Node) FlowNodeData() *FlowNodeBase { return n.data.FlowNodeData() }
+func (n *Node) DeclarationData() *DeclarationBase { return n.data.DeclarationData() }
+func (n *Node) ExportableData() *ExportableBase { return n.data.ExportableData() }
+func (n *Node) LocalsContainerData() *LocalsContainerBase { return n.data.LocalsContainerData() }
+func (n *Node) FunctionLikeData() *FunctionLikeBase { return n.data.FunctionLikeData() }
+func (n *Node) ClassLikeData() *ClassLikeBase { return n.data.ClassLikeData() }
+func (n *Node) BodyData() *BodyBase { return n.data.BodyData() }
+
+// Node casts
+
+func (n *Node) AsIdentifier() *Identifier {
+ return n.data.(*Identifier)
+}
+func (n *Node) AsPrivateIdentifier() *PrivateIdentifier {
+ return n.data.(*PrivateIdentifier)
+}
+func (n *Node) AsQualifiedName() *QualifiedName {
+ return n.data.(*QualifiedName)
+}
+func (n *Node) AsModifierList() *ModifierList {
+ return n.data.(*ModifierList)
+}
+func (n *Node) AsSourceFile() *SourceFile {
+ return n.data.(*SourceFile)
+}
+func (n *Node) AsPrefixUnaryExpression() *PrefixUnaryExpression {
+ return n.data.(*PrefixUnaryExpression)
+}
+func (n *Node) AsPostfixUnaryExpression() *PostfixUnaryExpression {
+ return n.data.(*PostfixUnaryExpression)
+}
+func (n *Node) AsParenthesizedExpression() *ParenthesizedExpression {
+ return n.data.(*ParenthesizedExpression)
+}
+func (n *Node) AsTypeAssertion() *TypeAssertion {
+ return n.data.(*TypeAssertion)
+}
+func (n *Node) AsAsExpression() *AsExpression {
+ return n.data.(*AsExpression)
+}
+func (n *Node) AsSatisfiesExpression() *SatisfiesExpression {
+ return n.data.(*SatisfiesExpression)
+}
+func (n *Node) AsExpressionWithTypeArguments() *ExpressionWithTypeArguments {
+ return n.data.(*ExpressionWithTypeArguments)
+}
+func (n *Node) AsNonNullExpression() *NonNullExpression {
+ return n.data.(*NonNullExpression)
+}
+func (n *Node) AsBindingElement() *BindingElement {
+ return n.data.(*BindingElement)
+}
+func (n *Node) AsImportSpecifier() *ImportSpecifier {
+ return n.data.(*ImportSpecifier)
+}
+func (n *Node) AsArrowFunction() *ArrowFunction {
+ return n.data.(*ArrowFunction)
+}
+func (n *Node) AsCallExpression() *CallExpression {
+ return n.data.(*CallExpression)
+}
+func (n *Node) AsPropertyAccessExpression() *PropertyAccessExpression {
+ return n.data.(*PropertyAccessExpression)
+}
+func (n *Node) AsElementAccessExpression() *ElementAccessExpression {
+ return n.data.(*ElementAccessExpression)
+}
+func (n *Node) AsComputedPropertyName() *ComputedPropertyName {
+ return n.data.(*ComputedPropertyName)
+}
+func (n *Node) AsBinaryExpression() *BinaryExpression {
+ return n.data.(*BinaryExpression)
+}
+func (n *Node) AsModuleDeclaration() *ModuleDeclaration {
+ return n.data.(*ModuleDeclaration)
+}
+func (n *Node) AsStringLiteral() *StringLiteral {
+ return n.data.(*StringLiteral)
+}
+func (n *Node) AsNumericLiteral() *NumericLiteral {
+ return n.data.(*NumericLiteral)
+}
+func (n *Node) AsBigintLiteral() *BigintLiteral {
+ return n.data.(*BigintLiteral)
+}
+func (n *Node) AsNoSubstitutionTemplateLiteral() *NoSubstitutionTemplateLiteral {
+ return n.data.(*NoSubstitutionTemplateLiteral)
+}
+func (n *Node) AsVariableDeclaration() *VariableDeclaration {
+ return n.data.(*VariableDeclaration)
+}
+func (n *Node) AsExportAssignment() *ExportAssignment {
+ return n.data.(*ExportAssignment)
+}
+func (n *Node) AsObjectLiteralExpression() *ObjectLiteralExpression {
+ return n.data.(*ObjectLiteralExpression)
+}
+func (n *Node) AsIfStatement() *IfStatement {
+ return n.data.(*IfStatement)
+}
+func (n *Node) AsWhileStatement() *WhileStatement {
+ return n.data.(*WhileStatement)
+}
+func (n *Node) AsDoStatement() *DoStatement {
+ return n.data.(*DoStatement)
+}
+func (n *Node) AsForStatement() *ForStatement {
+ return n.data.(*ForStatement)
+}
+func (n *Node) AsConditionalExpression() *ConditionalExpression {
+ return n.data.(*ConditionalExpression)
+}
+func (n *Node) AsForInOrOfStatement() *ForInOrOfStatement {
+ return n.data.(*ForInOrOfStatement)
+}
+func (n *Node) AsShorthandPropertyAssignment() *ShorthandPropertyAssignment {
+ return n.data.(*ShorthandPropertyAssignment)
+}
+func (n *Node) AsPropertyAssignment() *PropertyAssignment {
+ return n.data.(*PropertyAssignment)
+}
+func (n *Node) AsExpressionStatement() *ExpressionStatement {
+ return n.data.(*ExpressionStatement)
+}
+func (n *Node) AsBlock() *Block {
+ return n.data.(*Block)
+}
+func (n *Node) AsModuleBlock() *ModuleBlock {
+ return n.data.(*ModuleBlock)
+}
+func (n *Node) AsVariableStatement() *VariableStatement {
+ return n.data.(*VariableStatement)
+}
+func (n *Node) AsVariableDeclarationList() *VariableDeclarationList {
+ return n.data.(*VariableDeclarationList)
+}
+func (n *Node) AsMetaProperty() *MetaProperty {
+ return n.data.(*MetaProperty)
+}
+func (n *Node) AsTypeReference() *TypeReferenceNode {
+ return n.data.(*TypeReferenceNode)
+}
+func (n *Node) AsConstructorDeclaration() *ConstructorDeclaration {
+ return n.data.(*ConstructorDeclaration)
+}
+func (n *Node) AsConditionalTypeNode() *ConditionalTypeNode {
+ return n.data.(*ConditionalTypeNode)
+}
+func (n *Node) AsClassExpression() *ClassExpression {
+ return n.data.(*ClassExpression)
+}
+func (n *Node) AsHeritageClause() *HeritageClause {
+ return n.data.(*HeritageClause)
+}
+func (n *Node) AsFunctionExpression() *FunctionExpression {
+ return n.data.(*FunctionExpression)
+}
+func (n *Node) AsParameterDeclaration() *ParameterDeclaration {
+ return n.data.(*ParameterDeclaration)
+}
+func (n *Node) AsInferTypeNode() *InferTypeNode {
+ return n.data.(*InferTypeNode)
+}
+func (n *Node) AsTypeParameter() *TypeParameterDeclaration {
+ return n.data.(*TypeParameterDeclaration)
+}
+func (n *Node) AsExportSpecifier() *ExportSpecifier {
+ return n.data.(*ExportSpecifier)
+}
+func (n *Node) AsExportDeclaration() *ExportDeclaration {
+ return n.data.(*ExportDeclaration)
+}
+func (n *Node) AsPropertyDeclaration() *PropertyDeclaration {
+ return n.data.(*PropertyDeclaration)
+}
+func (n *Node) AsImportClause() *ImportClause {
+ return n.data.(*ImportClause)
+}
+func (n *Node) AsImportEqualsDeclaration() *ImportEqualsDeclaration {
+ return n.data.(*ImportEqualsDeclaration)
+}
+func (n *Node) AsNamespaceImport() *NamespaceImport {
+ return n.data.(*NamespaceImport)
+}
+func (n *Node) AsPropertySignatureDeclaration() *PropertySignatureDeclaration {
+ return n.data.(*PropertySignatureDeclaration)
+}
+func (n *Node) AsEnumMember() *EnumMember {
+ return n.data.(*EnumMember)
+}
+func (n *Node) AsReturnStatement() *ReturnStatement {
+ return n.data.(*ReturnStatement)
+}
+func (n *Node) AsWithStatement() *WithStatement {
+ return n.data.(*WithStatement)
+}
+func (n *Node) AsSwitchStatement() *SwitchStatement {
+ return n.data.(*SwitchStatement)
+}
+func (n *Node) AsCaseOrDefaultClause() *CaseOrDefaultClause {
+ return n.data.(*CaseOrDefaultClause)
+}
+func (n *Node) AsThrowStatement() *ThrowStatement {
+ return n.data.(*ThrowStatement)
+}
+func (n *Node) AsTemplateSpan() *TemplateSpan {
+ return n.data.(*TemplateSpan)
+}
+func (n *Node) AsImportTypeNode() *ImportTypeNode {
+ return n.data.(*ImportTypeNode)
+}
+func (n *Node) AsNewExpression() *NewExpression {
+ return n.data.(*NewExpression)
+}
+func (n *Node) AsTaggedTemplateExpression() *TaggedTemplateExpression {
+ return n.data.(*TaggedTemplateExpression)
+}
+func (n *Node) AsTypeArgumentList() *TypeArgumentList {
+ return n.data.(*TypeArgumentList)
+}
+func (n *Node) AsJsxOpeningElement() *JsxOpeningElement {
+ return n.data.(*JsxOpeningElement)
+}
+func (n *Node) AsJsxSelfClosingElement() *JsxSelfClosingElement {
+ return n.data.(*JsxSelfClosingElement)
+}
+func (n *Node) AsJsxClosingElement() *JsxClosingElement {
+ return n.data.(*JsxClosingElement)
+}
+func (n *Node) AsImportDeclaration() *ImportDeclaration {
+ return n.data.(*ImportDeclaration)
+}
+func (n *Node) AsExternalModuleReference() *ExternalModuleReference {
+ return n.data.(*ExternalModuleReference)
+}
+func (n *Node) AsLiteralTypeNode() *LiteralTypeNode {
+ return n.data.(*LiteralTypeNode)
+}
+func (n *Node) AsJsxNamespacedName() *JsxNamespacedName {
+ return n.data.(*JsxNamespacedName)
+}
+func (n *Node) AsTypeParameterList() *TypeParameterList {
+ return n.data.(*TypeParameterList)
+}
+func (n *Node) AsClassDeclaration() *ClassDeclaration {
+ return n.data.(*ClassDeclaration)
+}
+func (n *Node) AsInterfaceDeclaration() *InterfaceDeclaration {
+ return n.data.(*InterfaceDeclaration)
+}
+func (n *Node) AsTypeAliasDeclaration() *TypeAliasDeclaration {
+ return n.data.(*TypeAliasDeclaration)
+}
+func (n *Node) AsJsxAttribute() *JsxAttribute {
+ return n.data.(*JsxAttribute)
+}
+func (n *Node) AsParenthesizedTypeNode() *ParenthesizedTypeNode {
+ return n.data.(*ParenthesizedTypeNode)
+}
+func (n *Node) AsTypePredicateNode() *TypePredicateNode {
+ return n.data.(*TypePredicateNode)
+}
+func (n *Node) AsTypeOperatorNode() *TypeOperatorNode {
+ return n.data.(*TypeOperatorNode)
+}
+func (n *Node) AsMappedTypeNode() *MappedTypeNode {
+ return n.data.(*MappedTypeNode)
+}
+func (n *Node) AsArrayLiteralExpression() *ArrayLiteralExpression {
+ return n.data.(*ArrayLiteralExpression)
+}
+func (n *Node) AsMethodDeclaration() *MethodDeclaration {
+ return n.data.(*MethodDeclaration)
+}
+func (n *Node) AsMethodSignatureDeclaration() *MethodSignatureDeclaration {
+ return n.data.(*MethodSignatureDeclaration)
+}
+func (n *Node) AsTemplateLiteralTypeSpan() *TemplateLiteralTypeSpan {
+ return n.data.(*TemplateLiteralTypeSpan)
+}
+func (n *Node) AsJsxElement() *JsxElement {
+ return n.data.(*JsxElement)
+}
+func (n *Node) AsKeywordExpression() *KeywordExpression {
+ return n.data.(*KeywordExpression)
+}
+func (n *Node) AsCatchClause() *CatchClause {
+ return n.data.(*CatchClause)
+}
+func (n *Node) AsDeleteExpression() *DeleteExpression {
+ return n.data.(*DeleteExpression)
+}
+func (n *Node) AsLabeledStatement() *LabeledStatement {
+ return n.data.(*LabeledStatement)
+}
+func (n *Node) AsNamespaceExportDeclaration() *NamespaceExportDeclaration {
+ return n.data.(*NamespaceExportDeclaration)
+}
+func (n *Node) AsNamedExports() *NamedExports {
+ return n.data.(*NamedExports)
+}
+func (n *Node) AsBreakStatement() *BreakStatement {
+ return n.data.(*BreakStatement)
+}
+func (n *Node) AsContinueStatement() *ContinueStatement {
+ return n.data.(*ContinueStatement)
+}
+func (n *Node) AsCaseBlock() *CaseBlock {
+ return n.data.(*CaseBlock)
+}
+func (n *Node) AsTryStatement() *TryStatement {
+ return n.data.(*TryStatement)
+}
+func (n *Node) AsBindingPattern() *BindingPattern {
+ return n.data.(*BindingPattern)
+}
+func (n *Node) AsFunctionDeclaration() *FunctionDeclaration {
+ return n.data.(*FunctionDeclaration)
+}
+func (n *Node) AsTypeOfExpression() *TypeOfExpression {
+ return n.data.(*TypeOfExpression)
+}
+func (n *Node) AsSpreadElement() *SpreadElement {
+ return n.data.(*SpreadElement)
+}
+func (n *Node) AsSpreadAssignment() *SpreadAssignment {
+ return n.data.(*SpreadAssignment)
+}
+func (n *Node) AsArrayTypeNode() *ArrayTypeNode {
+ return n.data.(*ArrayTypeNode)
+}
+func (n *Node) AsTupleTypeNode() *TupleTypeNode {
+ return n.data.(*TupleTypeNode)
+}
+
+// NodeData
+
+type NodeData interface {
+ AsNode() *Node
+ ForEachChild(v Visitor) bool
+ Symbol() *Symbol
+ LocalSymbol() *Symbol
+ Modifiers() *ModifierListNode
+ Name() *DeclarationName
+ FlowNodeData() *FlowNodeBase
+ DeclarationData() *DeclarationBase
+ ExportableData() *ExportableBase
+ LocalsContainerData() *LocalsContainerBase
+ FunctionLikeData() *FunctionLikeBase
+ ClassLikeData() *ClassLikeBase
+ BodyData() *BodyBase
+}
+
+// NodeDefault
+
+type NodeDefault struct {
+ Node
+}
+
+func (node *NodeDefault) AsNode() *Node { return &node.Node }
+func (node *NodeDefault) ForEachChild(v Visitor) bool { return false }
+func (node *NodeDefault) Symbol() *Symbol { return nil }
+func (node *NodeDefault) LocalSymbol() *Symbol { return nil }
+func (node *NodeDefault) Modifiers() *ModifierListNode { return nil }
+func (node *NodeDefault) Name() *DeclarationName { return nil }
+func (node *NodeDefault) FlowNodeData() *FlowNodeBase { return nil }
+func (node *NodeDefault) DeclarationData() *DeclarationBase { return nil }
+func (node *NodeDefault) ExportableData() *ExportableBase { return nil }
+func (node *NodeDefault) LocalsContainerData() *LocalsContainerBase { return nil }
+func (node *NodeDefault) FunctionLikeData() *FunctionLikeBase { return nil }
+func (node *NodeDefault) ClassLikeData() *ClassLikeBase { return nil }
+func (node *NodeDefault) BodyData() *BodyBase { return nil }
+
+// NodeBase
+
+type NodeBase struct {
+ NodeDefault
+}
+
+// Aliases for Node unions
+
+type Statement = Node // Node with StatementBase
+type Declaration = Node // Node with DeclarationBase
+type Expression = Node // Node with ExpressionBase
+type TypeNode = Node // Node with TypeNodeBase
+type TypeElement = Node // Node with TypeElementBase
+type ClassElement = Node // Node with ClassElementBase
+type NamedMember = Node // Node with NamedMemberBase
+type ObjectLiteralElement = Node // Node with ObjectLiteralElementBase
+type BlockOrExpression = Node // Block | Expression
+type AccessExpression = Node // PropertyAccessExpression | ElementAccessExpression
+type DeclarationName = Node // Identifier | PrivateIdentifier | StringLiteral | NumericLiteral | BigIntLiteral | NoSubstitutionTemplateLiteral | ComputedPropertyName | BindingPattern | ElementAccessExpression
+type ModuleName = Node // Identifier | StringLiteral
+type ModuleExportName = Node // Identifier | StringLiteral
+type PropertyName = Node // Identifier | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier | BigIntLiteral
+type ModuleBody = Node // ModuleBlock | ModuleDeclaration
+type ForInitializer = Node // Expression | MissingDeclaration | VariableDeclarationList
+type ModuleReference = Node // Identifier | QualifiedName | ExternalModuleReference
+type NamedImportBindings = Node // NamespaceImport | NamedImports
+type NamedExportBindings = Node // NamespaceExport | NamedExports
+type MemberName = Node // Identifier | PrivateIdentifier
+type EntityName = Node // Identifier | QualifiedName
+type BindingName = Node // Identifier | BindingPattern
+type ModifierLike = Node // Modifier | Decorator
+type JsxAttributeLike = Node // JsxAttribute | JsxSpreadAttribute
+type JsxAttributeName = Node // Identifier | JsxNamespacedName
+type ClassLikeDeclaration = Node // ClassDeclaration | ClassExpression
+type AccessorDeclaration = Node // GetAccessorDeclaration | SetAccessorDeclaration
+type LiteralLikeNode = Node // StringLiteral | NumericLiteral | BigintLiteral | RegularExpressionLiteral | TemplateLiteralLikeNode | JsxText
+type LiteralExpression = Node // StringLiteral | NumericLiteral | BigintLiteral | RegularExpressionLiteral | NoSubstitutionTemplateLiteral
+type UnionOrIntersectionTypeNode = Node // UnionTypeNode | IntersectionTypeNode
+type TemplateLiteralLikeNode = Node // TemplateHead | TemplateMiddle | TemplateTail
+type TemplateMiddleOrTail = Node // TemplateMiddle | TemplateTail
+
+// Aliases for node signletons
+
+type IdentifierNode = Node
+type ModifierListNode = Node
+type TokenNode = Node
+type BlockNode = Node
+type CatchClauseNode = Node
+type CaseBlockNode = Node
+type CaseOrDefaultClauseNode = Node
+type VariableDeclarationNode = Node
+type VariableDeclarationListNode = Node
+type BindingElementNode = Node
+type TypeParameterListNode = Node
+type ParameterDeclarationNode = Node
+type HeritageClauseNode = Node
+type ExpressionWithTypeArgumentsNode = Node
+type EnumMemberNode = Node
+type ImportClauseNode = Node
+type ImportAttributesNode = Node
+type ImportSpecifierNode = Node
+type ExportSpecifierNode = Node
+
+// DeclarationBase
+
+type DeclarationBase struct {
+ symbol *Symbol // Symbol declared by node (initialized by binding)
+}
+
+func (node *DeclarationBase) Symbol() *Symbol { return node.symbol }
+func (node *DeclarationBase) DeclarationData() *DeclarationBase { return node }
+
+// DeclarationBase
+
+type ExportableBase struct {
+ localSymbol *Symbol // Local symbol declared by node (initialized by binding only for exported nodes)
+}
+
+func (node *ExportableBase) LocalSymbol() *Symbol { return node.localSymbol }
+func (node *ExportableBase) ExportableData() *ExportableBase { return node }
+
+// ModifiersBase
+
+type ModifiersBase struct {
+ modifiers *ModifierListNode
+}
+
+func (node *ModifiersBase) Modifiers() *ModifierListNode { return node.modifiers }
+
+// LocalsContainerBase
+
+type LocalsContainerBase struct {
+ locals SymbolTable // Locals associated with node (initialized by binding)
+ nextContainer *Node // Next container in declaration order (initialized by binding)
+}
+
+func (node *LocalsContainerBase) LocalsContainerData() *LocalsContainerBase { return node }
+
+func isLocalsContainer(node *Node) bool {
+ return node.LocalsContainerData() != nil
+}
+
+// FunctionLikeBase
+
+type FunctionLikeBase struct {
+ LocalsContainerBase
+ typeParameters *TypeParameterListNode // Optional
+ parameters []*ParameterDeclarationNode
+ returnType *TypeNode // Optional
+}
+
+func (node *FunctionLikeBase) LocalsContainerData() *LocalsContainerBase {
+ return &node.LocalsContainerBase
+}
+func (node *FunctionLikeBase) FunctionLikeData() *FunctionLikeBase { return node }
+func (node *FunctionLikeBase) BodyData() *BodyBase { return nil }
+
+// BodyBase
+
+type BodyBase struct {
+ asteriskToken *TokenNode
+ body *BlockOrExpression // Optional, can be Expression only in arrow functions
+ endFlowNode *FlowNode
+}
+
+func (node *BodyBase) BodyData() *BodyBase { return node }
+
+// FunctionLikeWithBodyBase
+
+type FunctionLikeWithBodyBase struct {
+ FunctionLikeBase
+ BodyBase
+}
+
+func (node *FunctionLikeWithBodyBase) LocalsContainerData() *LocalsContainerBase {
+ return &node.LocalsContainerBase
+}
+func (node *FunctionLikeWithBodyBase) FunctionLikeData() *FunctionLikeBase {
+ return &node.FunctionLikeBase
+}
+func (node *FunctionLikeWithBodyBase) BodyData() *BodyBase { return &node.BodyBase }
+
+// FlowNodeBase
+
+type FlowNodeBase struct {
+ flowNode *FlowNode
+}
+
+func (node *FlowNodeBase) FlowNodeData() *FlowNodeBase { return node }
+
+// Token
+
+type Token struct {
+ NodeBase
+}
+
+func (f *NodeFactory) NewToken(kind SyntaxKind) *Node {
+ return f.NewNode(kind, &Token{})
+}
+
+// Identifier
+
+type Identifier struct {
+ ExpressionBase
+ FlowNodeBase
+ text string
+}
+
+func (f *NodeFactory) NewIdentifier(text string) *Node {
+ data := f.identifierPool.New()
+ data.text = text
+ return f.NewNode(SyntaxKindIdentifier, data)
+}
+
+func isIdentifier(node *Node) bool {
+ return node.kind == SyntaxKindIdentifier
+}
+
+// PrivateIdentifier
+
+type PrivateIdentifier struct {
+ ExpressionBase
+ text string
+}
+
+func (f *NodeFactory) NewPrivateIdentifier(text string) *Node {
+ data := &PrivateIdentifier{}
+ data.text = text
+ return f.NewNode(SyntaxKindPrivateIdentifier, data)
+}
+
+func isPrivateIdentifier(node *Node) bool {
+ return node.kind == SyntaxKindPrivateIdentifier
+}
+
+// QualifiedName
+
+type QualifiedName struct {
+ NodeBase
+ FlowNodeBase
+ left *EntityName
+ right *IdentifierNode
+}
+
+func (f *NodeFactory) NewQualifiedName(left *EntityName, right *IdentifierNode) *Node {
+ data := &QualifiedName{}
+ data.left = left
+ data.right = right
+ return f.NewNode(SyntaxKindQualifiedName, data)
+}
+
+func (node *QualifiedName) ForEachChild(v Visitor) bool {
+ return visit(v, node.left) || visit(v, node.right)
+}
+
+func isQualifiedName(node *Node) bool {
+ return node.kind == SyntaxKindQualifiedName
+}
+
+// TypeParameterDeclaration
+
+type TypeParameterDeclaration struct {
+ NodeBase
+ DeclarationBase
+ ModifiersBase
+ name *IdentifierNode // Identifier
+ constraint *TypeNode // Optional
+ defaultType *TypeNode // Optional
+ expression *Node // For error recovery purposes
+}
+
+func (f *NodeFactory) NewTypeParameterDeclaration(modifiers *Node, name *IdentifierNode, constraint *TypeNode, defaultType *TypeNode) *Node {
+ data := &TypeParameterDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ data.constraint = constraint
+ data.defaultType = defaultType
+ return f.NewNode(SyntaxKindTypeParameter, data)
+}
+
+func (node *TypeParameterDeclaration) Kind() SyntaxKind {
+ return SyntaxKindTypeParameter
+}
+
+func (node *TypeParameterDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.constraint) || visit(v, node.defaultType)
+}
+
+func (node *TypeParameterDeclaration) Name() *DeclarationName {
+ return node.name
+}
+
+func isTypeParameterDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindTypeParameter
+}
+
+// ComputedPropertyName
+
+type ComputedPropertyName struct {
+ NodeBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewComputedPropertyName(expression *Node) *Node {
+ data := &ComputedPropertyName{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindComputedPropertyName, data)
+}
+
+func (node *ComputedPropertyName) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+func isComputedPropertyName(node *Node) bool {
+ return node.kind == SyntaxKindComputedPropertyName
+}
+
+// Modifier
+
+func (f *NodeFactory) NewModifier(kind SyntaxKind) *Node {
+ return f.NewToken(kind)
+}
+
+// Decorator
+
+type Decorator struct {
+ NodeBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewDecorator(expression *Node) *Node {
+ data := &Decorator{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindDecorator, data)
+}
+
+func (node *Decorator) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+// ModifierList
+
+type ModifierList struct {
+ NodeBase
+ modifiers []*ModifierLike
+ modifierFlags ModifierFlags
+}
+
+func (f *NodeFactory) NewModifierList(modifiers []*ModifierLike, modifierFlags ModifierFlags) *Node {
+ data := &ModifierList{}
+ data.modifiers = modifiers
+ data.modifierFlags = modifierFlags
+ return f.NewNode(SyntaxKindModifierList, data)
+}
+
+func (node *ModifierList) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.modifiers)
+}
+
+// StatementBase
+
+type StatementBase struct {
+ NodeBase
+ FlowNodeBase
+}
+
+// EmptyStatement
+
+type EmptyStatement struct {
+ StatementBase
+}
+
+func (f *NodeFactory) NewEmptyStatement() *Node {
+ return f.NewNode(SyntaxKindEmptyStatement, &EmptyStatement{})
+}
+
+func isEmptyStatement(node *Node) bool {
+ return node.kind == SyntaxKindEmptyStatement
+}
+
+// IfStatement
+
+type IfStatement struct {
+ StatementBase
+ expression *Node
+ thenStatement *Statement
+ elseStatement *Statement // Optional
+}
+
+func (f *NodeFactory) NewIfStatement(expression *Node, thenStatement *Statement, elseStatement *Statement) *Node {
+ data := &IfStatement{}
+ data.expression = expression
+ data.thenStatement = thenStatement
+ data.elseStatement = elseStatement
+ return f.NewNode(SyntaxKindIfStatement, data)
+}
+
+func (node *IfStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.thenStatement) || visit(v, node.elseStatement)
+}
+
+// DoStatement
+
+type DoStatement struct {
+ StatementBase
+ statement *Statement
+ expression *Node
+}
+
+func (f *NodeFactory) NewDoStatement(statement *Statement, expression *Node) *Node {
+ data := &DoStatement{}
+ data.statement = statement
+ data.expression = expression
+ return f.NewNode(SyntaxKindDoStatement, data)
+}
+
+func (node *DoStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.statement) || visit(v, node.expression)
+}
+
+// WhileStatement
+
+type WhileStatement struct {
+ StatementBase
+ expression *Node
+ statement *Statement
+}
+
+func (f *NodeFactory) NewWhileStatement(expression *Node, statement *Statement) *Node {
+ data := &WhileStatement{}
+ data.expression = expression
+ data.statement = statement
+ return f.NewNode(SyntaxKindWhileStatement, data)
+}
+
+func (node *WhileStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.statement)
+}
+
+// ForStatement
+
+type ForStatement struct {
+ StatementBase
+ LocalsContainerBase
+ initializer *ForInitializer // Optional
+ condition *Node // Optional
+ incrementor *Node // Optional
+ statement *Statement
+}
+
+func (f *NodeFactory) NewForStatement(initializer *ForInitializer, condition *Node, incrementor *Node, statement *Statement) *Node {
+ data := &ForStatement{}
+ data.initializer = initializer
+ data.condition = condition
+ data.incrementor = incrementor
+ data.statement = statement
+ return f.NewNode(SyntaxKindForStatement, data)
+}
+
+func (node *ForStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.initializer) || visit(v, node.condition) || visit(v, node.incrementor) || visit(v, node.statement)
+}
+
+// ForInOrOfStatement
+
+type ForInOrOfStatement struct {
+ StatementBase
+ LocalsContainerBase
+ kind SyntaxKind // SyntaxKindForInStatement | SyntaxKindForOfStatement
+ awaitModifier *Node // Optional
+ initializer *ForInitializer
+ expression *Node
+ statement *Statement
+}
+
+func (f *NodeFactory) NewForInOrOfStatement(kind SyntaxKind, awaitModifier *Node, initializer *ForInitializer, expression *Node, statement *Statement) *Node {
+ data := &ForInOrOfStatement{}
+ data.kind = kind
+ data.awaitModifier = awaitModifier
+ data.initializer = initializer
+ data.expression = expression
+ data.statement = statement
+ return f.NewNode(kind, data)
+}
+
+func (node *ForInOrOfStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.awaitModifier) || visit(v, node.initializer) || visit(v, node.expression) || visit(v, node.statement)
+}
+
+func isForInOrOfStatement(node *Node) bool {
+ return node.kind == SyntaxKindForInStatement || node.kind == SyntaxKindForOfStatement
+}
+
+// BreakStatement
+
+type BreakStatement struct {
+ StatementBase
+ label *IdentifierNode // Optional
+}
+
+func (f *NodeFactory) NewBreakStatement(label *IdentifierNode) *Node {
+ data := &BreakStatement{}
+ data.label = label
+ return f.NewNode(SyntaxKindBreakStatement, data)
+}
+
+func (node *BreakStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.label)
+}
+
+// ContinueStatement
+
+type ContinueStatement struct {
+ StatementBase
+ label *IdentifierNode // Optional
+}
+
+func (f *NodeFactory) NewContinueStatement(label *IdentifierNode) *Node {
+ data := &ContinueStatement{}
+ data.label = label
+ return f.NewNode(SyntaxKindContinueStatement, data)
+}
+
+func (node *ContinueStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.label)
+}
+
+// ReturnStatement
+
+type ReturnStatement struct {
+ StatementBase
+ expression *Node // Optional
+}
+
+func (f *NodeFactory) NewReturnStatement(expression *Node) *Node {
+ data := &ReturnStatement{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindReturnStatement, data)
+}
+
+func (node *ReturnStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+// WithStatement
+
+type WithStatement struct {
+ StatementBase
+ expression *Node
+ statement *Statement
+}
+
+func (f *NodeFactory) NewWithStatement(expression *Node, statement *Statement) *Node {
+ data := &WithStatement{}
+ data.expression = expression
+ data.statement = statement
+ return f.NewNode(SyntaxKindWithStatement, data)
+}
+
+func (node *WithStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.statement)
+}
+
+// SwitchStatement
+
+type SwitchStatement struct {
+ StatementBase
+ expression *Node
+ caseBlock *CaseBlockNode
+}
+
+func (f *NodeFactory) NewSwitchStatement(expression *Node, caseBlock *CaseBlockNode) *Node {
+ data := &SwitchStatement{}
+ data.expression = expression
+ data.caseBlock = caseBlock
+ return f.NewNode(SyntaxKindSwitchStatement, data)
+}
+
+func (node *SwitchStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.caseBlock)
+}
+
+// CaseBlock
+
+type CaseBlock struct {
+ NodeBase
+ LocalsContainerBase
+ clauses []*CaseOrDefaultClauseNode
+}
+
+func (f *NodeFactory) NewCaseBlock(clauses []*CaseOrDefaultClauseNode) *Node {
+ data := &CaseBlock{}
+ data.clauses = clauses
+ return f.NewNode(SyntaxKindCaseBlock, data)
+}
+
+func (node *CaseBlock) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.clauses)
+}
+
+// CaseOrDefaultClause
+
+type CaseOrDefaultClause struct {
+ NodeBase
+ expression *Node // nil in default clause
+ statements []*Statement
+ fallthroughFlowNode *FlowNode
+}
+
+func (f *NodeFactory) NewCaseOrDefaultClause(kind SyntaxKind, expression *Node, statements []*Statement) *Node {
+ data := &CaseOrDefaultClause{}
+ data.expression = expression
+ data.statements = statements
+ return f.NewNode(kind, data)
+}
+
+func (node *CaseOrDefaultClause) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visitNodes(v, node.statements)
+}
+
+// ThrowStatement
+
+type ThrowStatement struct {
+ StatementBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewThrowStatement(expression *Node) *Node {
+ data := &ThrowStatement{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindThrowStatement, data)
+}
+
+func (node *ThrowStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+// TryStatement
+
+type TryStatement struct {
+ StatementBase
+ tryBlock *BlockNode
+ catchClause *CatchClauseNode // Optional
+ finallyBlock *BlockNode // Optional
+}
+
+func (f *NodeFactory) NewTryStatement(tryBlock *BlockNode, catchClause *CatchClauseNode, finallyBlock *BlockNode) *Node {
+ data := &TryStatement{}
+ data.tryBlock = tryBlock
+ data.catchClause = catchClause
+ data.finallyBlock = finallyBlock
+ return f.NewNode(SyntaxKindTryStatement, data)
+}
+
+func (node *TryStatement) Kind() SyntaxKind {
+ return SyntaxKindTryStatement
+}
+
+func (node *TryStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.tryBlock) || visit(v, node.catchClause) || visit(v, node.finallyBlock)
+}
+
+// CatchClause
+
+type CatchClause struct {
+ NodeBase
+ LocalsContainerBase
+ variableDeclaration *VariableDeclarationNode // Optional
+ block *BlockNode
+}
+
+func (f *NodeFactory) NewCatchClause(variableDeclaration *VariableDeclarationNode, block *BlockNode) *Node {
+ data := &CatchClause{}
+ data.variableDeclaration = variableDeclaration
+ data.block = block
+ return f.NewNode(SyntaxKindCatchClause, data)
+}
+
+func (node *CatchClause) ForEachChild(v Visitor) bool {
+ return visit(v, node.variableDeclaration) || visit(v, node.block)
+}
+
+// DebuggerStatement
+
+type DebuggerStatement struct {
+ StatementBase
+}
+
+func (f *NodeFactory) NewDebuggerStatement() *Node {
+ return f.NewNode(SyntaxKindDebuggerStatement, &DebuggerStatement{})
+}
+
+// LabeledStatement
+
+type LabeledStatement struct {
+ StatementBase
+ label *IdentifierNode
+ statement *Statement
+}
+
+func (f *NodeFactory) NewLabeledStatement(label *IdentifierNode, statement *Statement) *Node {
+ data := &LabeledStatement{}
+ data.label = label
+ data.statement = statement
+ return f.NewNode(SyntaxKindLabeledStatement, data)
+}
+
+func (node *LabeledStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.label) || visit(v, node.statement)
+}
+
+// ExpressionStatement
+
+type ExpressionStatement struct {
+ StatementBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewExpressionStatement(expression *Node) *Node {
+ data := &ExpressionStatement{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindExpressionStatement, data)
+}
+
+func (node *ExpressionStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+func isExpressionStatement(node *Node) bool {
+ return node.kind == SyntaxKindExpressionStatement
+}
+
+// Block
+
+type Block struct {
+ StatementBase
+ LocalsContainerBase
+ statements []*Statement
+ multiline bool
+}
+
+func (f *NodeFactory) NewBlock(statements []*Statement, multiline bool) *Node {
+ data := &Block{}
+ data.statements = statements
+ data.multiline = multiline
+ return f.NewNode(SyntaxKindBlock, data)
+}
+
+func (node *Block) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.statements)
+}
+
+func isBlock(node *Node) bool {
+ return node.kind == SyntaxKindBlock
+}
+
+// VariableStatement
+
+type VariableStatement struct {
+ StatementBase
+ ModifiersBase
+ declarationList *VariableDeclarationListNode
+}
+
+func (f *NodeFactory) NewVariableStatement(modifiers *ModifierListNode, declarationList *VariableDeclarationListNode) *Node {
+ data := &VariableStatement{}
+ data.modifiers = modifiers
+ data.declarationList = declarationList
+ return f.NewNode(SyntaxKindVariableStatement, data)
+}
+
+func (node *VariableStatement) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.declarationList)
+}
+
+func isVariableStatement(node *Node) bool {
+ return node.kind == SyntaxKindVariableStatement
+}
+
+// VariableDeclaration
+
+type VariableDeclaration struct {
+ NodeBase
+ DeclarationBase
+ ExportableBase
+ name *BindingName
+ exclamationToken *TokenNode // Optional
+ typeNode *TypeNode // Optional
+ initializer *Node // Optional
+}
+
+func (f *NodeFactory) NewVariableDeclaration(name *BindingName, exclamationToken *TokenNode, typeNode *TypeNode, initializer *Node) *Node {
+ data := &VariableDeclaration{}
+ data.name = name
+ data.exclamationToken = exclamationToken
+ data.typeNode = typeNode
+ data.initializer = initializer
+ return f.NewNode(SyntaxKindVariableDeclaration, data)
+}
+
+func (node *VariableDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.name) || visit(v, node.exclamationToken) || visit(v, node.typeNode) || visit(v, node.initializer)
+}
+
+func (node *VariableDeclaration) Name() *DeclarationName {
+ return node.name
+}
+
+func isVariableDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindVariableDeclaration
+}
+
+// VariableDeclarationList
+
+type VariableDeclarationList struct {
+ NodeBase
+ declarations []*VariableDeclarationNode
+}
+
+func (f *NodeFactory) NewVariableDeclarationList(flags NodeFlags, declarations []*VariableDeclarationNode) *Node {
+ data := &VariableDeclarationList{}
+ data.declarations = declarations
+ node := f.NewNode(SyntaxKindVariableDeclarationList, data)
+ node.flags = flags
+ return node
+}
+
+func (node *VariableDeclarationList) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.declarations)
+}
+
+// BindingPattern (SyntaxBindObjectBindingPattern | SyntaxKindArrayBindingPattern)
+
+type BindingPattern struct {
+ NodeBase
+ elements []*BindingElementNode
+}
+
+func (f *NodeFactory) NewBindingPattern(kind SyntaxKind, elements []*BindingElementNode) *Node {
+ data := &BindingPattern{}
+ data.elements = elements
+ return f.NewNode(kind, data)
+}
+
+func (node *BindingPattern) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.elements)
+}
+
+func isObjectBindingPattern(node *Node) bool {
+ return node.kind == SyntaxKindObjectBindingPattern
+}
+
+func isArrayBindingPattern(node *Node) bool {
+ return node.kind == SyntaxKindArrayBindingPattern
+}
+
+// ParameterDeclaration
+
+type ParameterDeclaration struct {
+ NodeBase
+ DeclarationBase
+ ModifiersBase
+ dotDotDotToken *TokenNode // Present on rest parameter
+ name *BindingName // Declared parameter name
+ questionToken *TokenNode // Present on optional parameter
+ typeNode *TypeNode // Optional
+ initializer *Node // Optional
+}
+
+func (f *NodeFactory) NewParameterDeclaration(modifiers *ModifierListNode, dotDotDotToken *TokenNode, name *BindingName, questionToken *TokenNode, typeNode *TypeNode, initializer *Node) *Node {
+ data := &ParameterDeclaration{}
+ data.modifiers = modifiers
+ data.dotDotDotToken = dotDotDotToken
+ data.name = name
+ data.questionToken = questionToken
+ data.typeNode = typeNode
+ data.initializer = initializer
+ return f.NewNode(SyntaxKindParameter, data)
+}
+
+func (node *ParameterDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.dotDotDotToken) || visit(v, node.name) ||
+ visit(v, node.questionToken) || visit(v, node.typeNode) || visit(v, node.initializer)
+}
+
+func (node *ParameterDeclaration) Name() *DeclarationName {
+ return node.name
+}
+
+func isParameter(node *Node) bool {
+ return node.kind == SyntaxKindParameter
+}
+
+// BindingElement
+
+type BindingElement struct {
+ NodeBase
+ DeclarationBase
+ ExportableBase
+ FlowNodeBase
+ dotDotDotToken *TokenNode // Present on rest element (in object binding pattern)
+ propertyName *PropertyName // Optional binding property name in object binding pattern
+ name *BindingName // Optional (nil for missing element)
+ initializer *Node // Optional
+}
+
+func (f *NodeFactory) NewBindingElement(dotDotDotToken *TokenNode, propertyName *PropertyName, name *BindingName, initializer *Node) *Node {
+ data := &BindingElement{}
+ data.dotDotDotToken = dotDotDotToken
+ data.propertyName = propertyName
+ data.name = name
+ data.initializer = initializer
+ return f.NewNode(SyntaxKindBindingElement, data)
+}
+
+func (node *BindingElement) ForEachChild(v Visitor) bool {
+ return visit(v, node.propertyName) || visit(v, node.dotDotDotToken) || visit(v, node.name) || visit(v, node.initializer)
+}
+
+func (node *BindingElement) Name() *DeclarationName {
+ return node.name
+}
+
+func isBindingElement(node *Node) bool {
+ return node.kind == SyntaxKindBindingElement
+}
+
+// MissingDeclaration
+
+type MissingDeclaration struct {
+ StatementBase
+ DeclarationBase
+ ModifiersBase
+}
+
+func (f *NodeFactory) NewMissingDeclaration(modifiers *ModifierListNode) *Node {
+ data := &MissingDeclaration{}
+ data.modifiers = modifiers
+ return f.NewNode(SyntaxKindMissingDeclaration, data)
+}
+
+func (node *MissingDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers)
+}
+
+// FunctionDeclaration
+
+type FunctionDeclaration struct {
+ StatementBase
+ DeclarationBase
+ ExportableBase
+ ModifiersBase
+ FunctionLikeWithBodyBase
+ name *IdentifierNode
+ returnFlowNode *FlowNode
+}
+
+func (f *NodeFactory) NewFunctionDeclaration(modifiers *ModifierListNode, asteriskToken *TokenNode, name *IdentifierNode, typeParameters *TypeParameterListNode, parameters []*ParameterDeclarationNode, returnType *TypeNode, body *BlockNode) *Node {
+ data := &FunctionDeclaration{}
+ data.modifiers = modifiers
+ data.asteriskToken = asteriskToken
+ data.name = name
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ data.body = body
+ return f.NewNode(SyntaxKindFunctionDeclaration, data)
+}
+
+func (node *FunctionDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.asteriskToken) || visit(v, node.name) || visit(v, node.typeParameters) ||
+ visitNodes(v, node.parameters) || visit(v, node.returnType) || visit(v, node.body)
+}
+
+func (node *FunctionDeclaration) Name() *DeclarationName {
+ return node.name
+}
+
+func (node *FunctionDeclaration) BodyData() *BodyBase { return &node.BodyBase }
+
+func isFunctionDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindFunctionDeclaration
+}
+
+// ClassLikeDeclarationBase
+
+type ClassLikeBase struct {
+ DeclarationBase
+ ExportableBase
+ ModifiersBase
+ name *IdentifierNode
+ typeParameters *TypeParameterListNode
+ heritageClauses []*HeritageClauseNode
+ members []*ClassElement
+}
+
+func (node *ClassLikeBase) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.typeParameters) ||
+ visitNodes(v, node.heritageClauses) || visitNodes(v, node.members)
+}
+
+func (node *ClassLikeBase) Name() *DeclarationName {
+ return node.name
+}
+
+func (node *ClassLikeBase) ClassLikeData() *ClassLikeBase { return node }
+
+// ClassDeclaration
+
+type ClassDeclaration struct {
+ StatementBase
+ ClassLikeBase
+}
+
+func (f *NodeFactory) NewClassDeclaration(modifiers *ModifierListNode, name *IdentifierNode, typeParameters *TypeParameterListNode, heritageClauses []*HeritageClauseNode, members []*ClassElement) *Node {
+ data := &ClassDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ data.typeParameters = typeParameters
+ data.heritageClauses = heritageClauses
+ data.members = members
+ return f.NewNode(SyntaxKindClassDeclaration, data)
+}
+
+func isClassDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindClassDeclaration
+}
+
+// ClassExpression
+
+type ClassExpression struct {
+ ExpressionBase
+ ClassLikeBase
+}
+
+func (f *NodeFactory) NewClassExpression(modifiers *ModifierListNode, name *IdentifierNode, typeParameters *TypeParameterListNode, heritageClauses []*HeritageClauseNode, members []*ClassElement) *Node {
+ data := &ClassExpression{}
+ data.modifiers = modifiers
+ data.name = name
+ data.typeParameters = typeParameters
+ data.heritageClauses = heritageClauses
+ data.members = members
+ return f.NewNode(SyntaxKindClassExpression, data)
+}
+
+func (node *ClassExpression) Kind() SyntaxKind { return SyntaxKindClassExpression }
+
+func isClassExpression(node *Node) bool {
+ return node.kind == SyntaxKindClassExpression
+}
+
+// HeritageClause
+
+type HeritageClause struct {
+ NodeBase
+ token SyntaxKind
+ types []*ExpressionWithTypeArgumentsNode
+}
+
+func (f *NodeFactory) NewHeritageClause(token SyntaxKind, types []*ExpressionWithTypeArgumentsNode) *Node {
+ data := &HeritageClause{}
+ data.token = token
+ data.types = types
+ return f.NewNode(SyntaxKindHeritageClause, data)
+}
+
+func (node *HeritageClause) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.types)
+}
+
+func isHeritageClause(node *Node) bool {
+ return node.kind == SyntaxKindHeritageClause
+}
+
+// InterfaceDeclaration
+
+type InterfaceDeclaration struct {
+ StatementBase
+ DeclarationBase
+ ExportableBase
+ ModifiersBase
+ name *IdentifierNode
+ typeParameters *TypeParameterListNode
+ heritageClauses []*HeritageClauseNode
+ members []*TypeElement
+}
+
+func (f *NodeFactory) NewInterfaceDeclaration(modifiers *ModifierListNode, name *IdentifierNode, typeParameters *TypeParameterListNode, heritageClauses []*HeritageClauseNode, members []*TypeElement) *Node {
+ data := &InterfaceDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ data.typeParameters = typeParameters
+ data.heritageClauses = heritageClauses
+ data.members = members
+ return f.NewNode(SyntaxKindInterfaceDeclaration, data)
+}
+
+func (node *InterfaceDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.typeParameters) ||
+ visitNodes(v, node.heritageClauses) || visitNodes(v, node.members)
+}
+
+func (node *InterfaceDeclaration) Name() *DeclarationName {
+ return node.name
+}
+
+func isInterfaceDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindInterfaceDeclaration
+}
+
+// TypeAliasDeclaration
+
+type TypeAliasDeclaration struct {
+ StatementBase
+ DeclarationBase
+ ExportableBase
+ ModifiersBase
+ LocalsContainerBase
+ name *IdentifierNode
+ typeParameters *TypeParameterListNode
+ typeNode *TypeNode
+}
+
+func (f *NodeFactory) NewTypeAliasDeclaration(modifiers *ModifierListNode, name *IdentifierNode, typeParameters *TypeParameterListNode, typeNode *TypeNode) *Node {
+ data := &TypeAliasDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ data.typeParameters = typeParameters
+ data.typeNode = typeNode
+ return f.NewNode(SyntaxKindTypeAliasDeclaration, data)
+}
+
+func (node *TypeAliasDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.typeParameters) || visit(v, node.typeNode)
+}
+
+func (node *TypeAliasDeclaration) Name() *DeclarationName {
+ return node.name
+}
+
+func isTypeAliasDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindTypeAliasDeclaration
+}
+
+// EnumMember
+
+type EnumMember struct {
+ NodeBase
+ NamedMemberBase
+ initializer *Node // Optional
+}
+
+func (f *NodeFactory) NewEnumMember(name *PropertyName, initializer *Node) *Node {
+ data := &EnumMember{}
+ data.name = name
+ data.initializer = initializer
+ return f.NewNode(SyntaxKindEnumMember, data)
+}
+
+func (node *EnumMember) ForEachChild(v Visitor) bool {
+ return visit(v, node.name) || visit(v, node.initializer)
+}
+
+func (node *EnumMember) Name() *DeclarationName {
+ return node.name
+}
+
+// EnumDeclaration
+
+type EnumDeclaration struct {
+ StatementBase
+ DeclarationBase
+ ExportableBase
+ ModifiersBase
+ name *IdentifierNode
+ members []*EnumMemberNode
+}
+
+func (f *NodeFactory) NewEnumDeclaration(modifiers *ModifierListNode, name *IdentifierNode, members []*EnumMemberNode) *Node {
+ data := &EnumDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ data.members = members
+ return f.NewNode(SyntaxKindEnumDeclaration, data)
+}
+
+func (node *EnumDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visitNodes(v, node.members)
+}
+
+func (node *EnumDeclaration) Name() *DeclarationName {
+ return node.name
+}
+
+func isEnumDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindEnumDeclaration
+}
+
+// ModuleBlock
+
+type ModuleBlock struct {
+ StatementBase
+ statements []*Statement
+}
+
+func (f *NodeFactory) NewModuleBlock(statements []*Statement) *Node {
+ data := &ModuleBlock{}
+ data.statements = statements
+ return f.NewNode(SyntaxKindModuleBlock, data)
+}
+
+func (node *ModuleBlock) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.statements)
+}
+
+func isModuleBlock(node *Node) bool {
+ return node.kind == SyntaxKindModuleBlock
+}
+
+// ModuleDeclaration
+
+type ModuleDeclaration struct {
+ StatementBase
+ DeclarationBase
+ ExportableBase
+ ModifiersBase
+ LocalsContainerBase
+ name *ModuleName
+ body *ModuleBody // Optional (may be nil in ambient module declaration)
+}
+
+func (f *NodeFactory) NewModuleDeclaration(modifiers *ModifierListNode, name *ModuleName, body *ModuleBody, flags NodeFlags) *Node {
+ data := &ModuleDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ data.body = body
+ node := f.NewNode(SyntaxKindModuleDeclaration, data)
+ node.flags |= flags & (NodeFlagsNamespace | NodeFlagsNestedNamespace | NodeFlagsGlobalAugmentation)
+ return node
+}
+
+func (node *ModuleDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.body)
+}
+
+func (node *ModuleDeclaration) Name() *DeclarationName {
+ return node.name
+}
+
+func isModuleDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindModuleDeclaration
+}
+
+// ModuleEqualsDeclaration
+
+type ImportEqualsDeclaration struct {
+ StatementBase
+ DeclarationBase
+ ExportableBase
+ ModifiersBase
+ modifiers *ModifierListNode
+ isTypeOnly bool
+ name *IdentifierNode
+ // 'EntityName' for an internal module reference, 'ExternalModuleReference' for an external
+ // module reference.
+ moduleReference *ModuleReference
+}
+
+func (f *NodeFactory) NewImportEqualsDeclaration(modifiers *ModifierListNode, isTypeOnly bool, name *IdentifierNode, moduleReference *ModuleReference) *Node {
+ data := &ImportEqualsDeclaration{}
+ data.modifiers = modifiers
+ data.isTypeOnly = isTypeOnly
+ data.name = name
+ data.moduleReference = moduleReference
+ return f.NewNode(SyntaxKindImportEqualsDeclaration, data)
+}
+
+func (node *ImportEqualsDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.moduleReference)
+}
+
+func (node *ImportEqualsDeclaration) Name() *DeclarationName {
+ return node.name
+}
+
+func isImportEqualsDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindImportEqualsDeclaration
+}
+
+// ImportDeclaration
+
+type ImportDeclaration struct {
+ StatementBase
+ ModifiersBase
+ importClause *ImportClauseNode
+ moduleSpecifier *Node
+ attributes *ImportAttributesNode
+}
+
+func (f *NodeFactory) NewImportDeclaration(modifiers *ModifierListNode, importClause *ImportClauseNode, moduleSpecifier *Node, attributes *ImportAttributesNode) *Node {
+ data := &ImportDeclaration{}
+ data.modifiers = modifiers
+ data.importClause = importClause
+ data.moduleSpecifier = moduleSpecifier
+ data.attributes = attributes
+ return f.NewNode(SyntaxKindImportDeclaration, data)
+}
+
+func (node *ImportDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.importClause) || visit(v, node.moduleSpecifier) || visit(v, node.attributes)
+}
+
+func isImportDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindImportDeclaration
+}
+
+// ImportSpecifier
+
+type ImportSpecifier struct {
+ NodeBase
+ DeclarationBase
+ ExportableBase
+ isTypeOnly bool
+ propertyName *ModuleExportName
+ name *IdentifierNode
+}
+
+func (f *NodeFactory) NewImportSpecifier(isTypeOnly bool, propertyName *ModuleExportName, name *IdentifierNode) *Node {
+ data := &ImportSpecifier{}
+ data.isTypeOnly = isTypeOnly
+ data.propertyName = propertyName
+ data.name = name
+ return f.NewNode(SyntaxKindImportSpecifier, data)
+}
+
+func (node *ImportSpecifier) ForEachChild(v Visitor) bool {
+ return visit(v, node.propertyName) || visit(v, node.name)
+}
+
+func (node *ImportSpecifier) Name() *DeclarationName {
+ return node.name
+}
+
+func isImportSpecifier(node *Node) bool {
+ return node.kind == SyntaxKindImportSpecifier
+}
+
+// ExternalModuleReference
+
+type ExternalModuleReference struct {
+ NodeBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewExternalModuleReference(expression *Node) *Node {
+ data := &ExternalModuleReference{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindExternalModuleReference, data)
+}
+
+func (node *ExternalModuleReference) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+func isExternalModuleReference(node *Node) bool {
+ return node.kind == SyntaxKindExternalModuleReference
+}
+
+// ImportClause
+
+type ImportClause struct {
+ NodeBase
+ DeclarationBase
+ ExportableBase
+ isTypeOnly bool
+ namedBindings *NamedImportBindings // Optional, named bindings
+ name *IdentifierNode // Optional, default binding
+}
+
+func (f *NodeFactory) NewImportClause(isTypeOnly bool, name *IdentifierNode, namedBindings *NamedImportBindings) *Node {
+ data := &ImportClause{}
+ data.isTypeOnly = isTypeOnly
+ data.name = name
+ data.namedBindings = namedBindings
+ return f.NewNode(SyntaxKindImportClause, data)
+}
+
+func (node *ImportClause) ForEachChild(v Visitor) bool {
+ return visit(v, node.name) || visit(v, node.namedBindings)
+}
+
+func (node *ImportClause) Name() *DeclarationName {
+ return node.name
+}
+
+// NamespaceImport
+
+type NamespaceImport struct {
+ NodeBase
+ DeclarationBase
+ ExportableBase
+ name *IdentifierNode
+}
+
+func (f *NodeFactory) NewNamespaceImport(name *IdentifierNode) *Node {
+ data := &NamespaceImport{}
+ data.name = name
+ return f.NewNode(SyntaxKindNamespaceImport, data)
+}
+
+func (node *NamespaceImport) ForEachChild(v Visitor) bool {
+ return visit(v, node.name)
+}
+
+func (node *NamespaceImport) Name() *DeclarationName {
+ return node.name
+}
+
+func isNamespaceImport(node *Node) bool {
+ return node.kind == SyntaxKindNamespaceImport
+}
+
+// NamedImports
+
+type NamedImports struct {
+ NodeBase
+ elements []*ImportSpecifierNode
+}
+
+func (f *NodeFactory) NewNamedImports(elements []*ImportSpecifierNode) *Node {
+ data := &NamedImports{}
+ data.elements = elements
+ return f.NewNode(SyntaxKindNamedImports, data)
+}
+
+func (node *NamedImports) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.elements)
+}
+
+// ExportAssignment
+
+// This is either an `export =` or an `export default` declaration.
+// Unless `isExportEquals` is set, this node was parsed as an `export default`.
+type ExportAssignment struct {
+ StatementBase
+ DeclarationBase
+ ModifiersBase
+ isExportEquals bool
+ expression *Node
+}
+
+func (f *NodeFactory) NewExportAssignment(modifiers *ModifierListNode, isExportEquals bool, expression *Node) *Node {
+ data := &ExportAssignment{}
+ data.modifiers = modifiers
+ data.isExportEquals = isExportEquals
+ data.expression = expression
+ return f.NewNode(SyntaxKindExportAssignment, data)
+}
+
+func (node *ExportAssignment) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.expression)
+}
+
+func isExportAssignment(node *Node) bool {
+ return node.kind == SyntaxKindExportAssignment
+}
+
+// NamespaceExportDeclaration
+
+type NamespaceExportDeclaration struct {
+ StatementBase
+ DeclarationBase
+ ModifiersBase
+ name *IdentifierNode
+}
+
+func (f *NodeFactory) NewNamespaceExportDeclaration(modifiers *ModifierListNode, name *IdentifierNode) *Node {
+ data := &NamespaceExportDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ return f.NewNode(SyntaxKindNamespaceExportDeclaration, data)
+}
+
+func (node *NamespaceExportDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name)
+}
+
+func (node *NamespaceExportDeclaration) Name() *DeclarationName {
+ return node.name
+}
+
+func isNamespaceExportDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindNamespaceExportDeclaration
+}
+
+// ExportDeclaration
+
+type ExportDeclaration struct {
+ StatementBase
+ DeclarationBase
+ ModifiersBase
+ isTypeOnly bool
+ exportClause *NamedExportBindings // Optional
+ moduleSpecifier *Node // Optional
+ attributes *ImportAttributesNode // Optional
+}
+
+func (f *NodeFactory) NewExportDeclaration(modifiers *ModifierListNode, isTypeOnly bool, exportClause *NamedExportBindings, moduleSpecifier *Node, attributes *ImportAttributesNode) *Node {
+ data := &ExportDeclaration{}
+ data.modifiers = modifiers
+ data.isTypeOnly = isTypeOnly
+ data.exportClause = exportClause
+ data.moduleSpecifier = moduleSpecifier
+ data.attributes = attributes
+ return f.NewNode(SyntaxKindExportDeclaration, data)
+}
+
+func (node *ExportDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.exportClause) || visit(v, node.moduleSpecifier) || visit(v, node.attributes)
+}
+
+func isExportDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindExportDeclaration
+}
+
+// NamespaceExport
+
+type NamespaceExport struct {
+ NodeBase
+ DeclarationBase
+ name *ModuleExportName
+}
+
+func (f *NodeFactory) NewNamespaceExport(name *ModuleExportName) *Node {
+ data := &NamespaceExport{}
+ data.name = name
+ return f.NewNode(SyntaxKindNamespaceExport, data)
+}
+
+func (node *NamespaceExport) ForEachChild(v Visitor) bool {
+ return visit(v, node.name)
+}
+
+func (node *NamespaceExport) Name() *DeclarationName {
+ return node.name
+}
+
+func isNamespaceExport(node *Node) bool {
+ return node.kind == SyntaxKindNamespaceExport
+}
+
+// NamedExports
+
+type NamedExports struct {
+ NodeBase
+ elements []*ExportSpecifierNode
+}
+
+func (f *NodeFactory) NewNamedExports(elements []*ExportSpecifierNode) *Node {
+ data := &NamedExports{}
+ data.elements = elements
+ return f.NewNode(SyntaxKindNamedExports, data)
+}
+
+func (node *NamedExports) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.elements)
+}
+
+// ExportSpecifier
+
+type ExportSpecifier struct {
+ NodeBase
+ DeclarationBase
+ ExportableBase
+ isTypeOnly bool
+ propertyName *ModuleExportName // Optional, name preceding 'as' keyword
+ name *ModuleExportName
+}
+
+func (f *NodeFactory) NewExportSpecifier(isTypeOnly bool, propertyName *ModuleExportName, name *ModuleExportName) *Node {
+ data := &ExportSpecifier{}
+ data.isTypeOnly = isTypeOnly
+ data.propertyName = propertyName
+ data.name = name
+ return f.NewNode(SyntaxKindExportSpecifier, data)
+}
+
+func (node *ExportSpecifier) ForEachChild(v Visitor) bool {
+ return visit(v, node.propertyName) || visit(v, node.name)
+}
+
+func (node *ExportSpecifier) Name() *DeclarationName {
+ return node.name
+}
+
+func isExportSpecifier(node *Node) bool {
+ return node.kind == SyntaxKindExportSpecifier
+}
+
+// TypeElementBase
+
+type TypeElementBase struct{}
+
+// ClassElementBase
+
+type ClassElementBase struct{}
+
+// NamedMemberBase
+
+type NamedMemberBase struct {
+ DeclarationBase
+ ModifiersBase
+ name *PropertyName
+ postfixToken *TokenNode
+}
+
+func (node *NamedMemberBase) Symbol() *Symbol { return node.symbol }
+func (node *NamedMemberBase) DeclarationData() *DeclarationBase { return &node.DeclarationBase }
+func (node *NamedMemberBase) Modifiers() *ModifierListNode { return node.modifiers }
+func (node *NamedMemberBase) Name() *DeclarationName { return node.name }
+
+// CallSignatureDeclaration
+
+type CallSignatureDeclaration struct {
+ NodeBase
+ DeclarationBase
+ FunctionLikeBase
+ TypeElementBase
+}
+
+func (f *NodeFactory) NewCallSignatureDeclaration(typeParameters *TypeParameterListNode, parameters []*ParameterDeclarationNode, returnType *Node) *Node {
+ data := &CallSignatureDeclaration{}
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ return f.NewNode(SyntaxKindCallSignature, data)
+}
+
+func (node *CallSignatureDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeParameters) || visitNodes(v, node.parameters) || visit(v, node.returnType)
+}
+
+func isCallSignatureDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindCallSignature
+}
+
+// ConstructSignatureDeclaration
+
+type ConstructSignatureDeclaration struct {
+ NodeBase
+ DeclarationBase
+ FunctionLikeBase
+ TypeElementBase
+}
+
+func (f *NodeFactory) NewConstructSignatureDeclaration(typeParameters *TypeParameterListNode, parameters []*ParameterDeclarationNode, returnType *Node) *Node {
+ data := &ConstructSignatureDeclaration{}
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ return f.NewNode(SyntaxKindConstructSignature, data)
+}
+
+func (node *ConstructSignatureDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeParameters) || visitNodes(v, node.parameters) || visit(v, node.returnType)
+}
+
+// ConstructorDeclaration
+
+type ConstructorDeclaration struct {
+ NodeBase
+ DeclarationBase
+ ModifiersBase
+ FunctionLikeWithBodyBase
+ ClassElementBase
+ returnFlowNode *FlowNode
+}
+
+func (f *NodeFactory) NewConstructorDeclaration(modifiers *ModifierListNode, typeParameters *TypeParameterListNode, parameters []*ParameterDeclarationNode, returnType *Node, body *BlockNode) *Node {
+ data := &ConstructorDeclaration{}
+ data.modifiers = modifiers
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ data.body = body
+ return f.NewNode(SyntaxKindConstructor, data)
+}
+
+func (node *ConstructorDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.typeParameters) || visitNodes(v, node.parameters) || visit(v, node.returnType) || visit(v, node.body)
+}
+
+func isConstructorDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindConstructor
+}
+
+// AccessorDeclarationBase
+
+type AccessorDeclarationBase struct {
+ NodeBase
+ NamedMemberBase
+ FunctionLikeWithBodyBase
+ FlowNodeBase
+ TypeElementBase
+ ClassElementBase
+ ObjectLiteralElementBase
+}
+
+func (node *AccessorDeclarationBase) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.typeParameters) || visitNodes(v, node.parameters) ||
+ visit(v, node.returnType) || visit(v, node.body)
+}
+
+func (node *AccessorDeclarationBase) isAccessorDeclaration() {}
+
+// GetAccessorDeclaration
+
+type GetAccessorDeclaration struct {
+ AccessorDeclarationBase
+}
+
+func (f *NodeFactory) NewGetAccessorDeclaration(modifiers *ModifierListNode, name *PropertyName, typeParameters *TypeParameterListNode, parameters []*ParameterDeclarationNode, returnType *Node, body *BlockNode) *Node {
+ data := &GetAccessorDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ data.body = body
+ return f.NewNode(SyntaxKindGetAccessor, data)
+}
+
+func isGetAccessorDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindGetAccessor
+}
+
+// SetAccessorDeclaration
+
+type SetAccessorDeclaration struct {
+ AccessorDeclarationBase
+}
+
+func (f *NodeFactory) NewSetAccessorDeclaration(modifiers *ModifierListNode, name *PropertyName, typeParameters *TypeParameterListNode, parameters []*ParameterDeclarationNode, returnType *Node, body *BlockNode) *Node {
+ data := &SetAccessorDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ data.body = body
+ return f.NewNode(SyntaxKindSetAccessor, data)
+}
+
+func isSetAccessorDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindSetAccessor
+}
+
+// IndexSignatureDeclaration
+
+type IndexSignatureDeclaration struct {
+ NodeBase
+ DeclarationBase
+ ModifiersBase
+ FunctionLikeBase
+ TypeElementBase
+ ClassElementBase
+}
+
+func (f *NodeFactory) NewIndexSignatureDeclaration(modifiers *Node, parameters []*Node, returnType *Node) *Node {
+ data := &IndexSignatureDeclaration{}
+ data.modifiers = modifiers
+ data.parameters = parameters
+ data.returnType = returnType
+ return f.NewNode(SyntaxKindIndexSignature, data)
+}
+
+func (node *IndexSignatureDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visitNodes(v, node.parameters) || visit(v, node.returnType)
+}
+
+// MethodSignatureDeclaration
+
+type MethodSignatureDeclaration struct {
+ NodeBase
+ NamedMemberBase
+ FunctionLikeBase
+ TypeElementBase
+}
+
+func (f *NodeFactory) NewMethodSignatureDeclaration(modifiers *Node, name *Node, postfixToken *Node, typeParameters *Node, parameters []*Node, returnType *Node) *Node {
+ data := &MethodSignatureDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ data.postfixToken = postfixToken
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ return f.NewNode(SyntaxKindMethodSignature, data)
+}
+
+func (node *MethodSignatureDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.postfixToken) || visit(v, node.typeParameters) ||
+ visitNodes(v, node.parameters) || visit(v, node.returnType)
+}
+
+func isMethodSignatureDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindMethodSignature
+}
+
+// MethodSignatureDeclaration
+
+type MethodDeclaration struct {
+ NodeBase
+ NamedMemberBase
+ FunctionLikeWithBodyBase
+ FlowNodeBase
+ ClassElementBase
+ ObjectLiteralElementBase
+}
+
+func (f *NodeFactory) NewMethodDeclaration(modifiers *Node, asteriskToken *Node, name *Node, postfixToken *Node, typeParameters *Node, parameters []*Node, returnType *Node, body *Node) *Node {
+ data := &MethodDeclaration{}
+ data.modifiers = modifiers
+ data.asteriskToken = asteriskToken
+ data.name = name
+ data.postfixToken = postfixToken
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ data.body = body
+ return f.NewNode(SyntaxKindMethodDeclaration, data)
+}
+
+func (node *MethodDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.asteriskToken) || visit(v, node.name) || visit(v, node.postfixToken) ||
+ visit(v, node.typeParameters) || visitNodes(v, node.parameters) || visit(v, node.returnType) || visit(v, node.body)
+}
+
+// PropertySignatureDeclaration
+
+type PropertySignatureDeclaration struct {
+ NodeBase
+ NamedMemberBase
+ TypeElementBase
+ typeNode *Node
+ initializer *Node // For error reporting purposes
+}
+
+func (f *NodeFactory) NewPropertySignatureDeclaration(modifiers *Node, name *Node, postfixToken *Node, typeNode *Node, initializer *Node) *Node {
+ data := &PropertySignatureDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ data.postfixToken = postfixToken
+ data.typeNode = typeNode
+ data.initializer = initializer
+ return f.NewNode(SyntaxKindPropertySignature, data)
+}
+
+func (node *PropertySignatureDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.postfixToken) || visit(v, node.typeNode) || visit(v, node.initializer)
+}
+
+func isPropertySignatureDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindPropertySignature
+}
+
+// PropertyDeclaration
+
+type PropertyDeclaration struct {
+ NodeBase
+ NamedMemberBase
+ ClassElementBase
+ typeNode *Node // Optional
+ initializer *Node // Optional
+}
+
+func (f *NodeFactory) NewPropertyDeclaration(modifiers *Node, name *Node, postfixToken *Node, typeNode *Node, initializer *Node) *Node {
+ data := &PropertyDeclaration{}
+ data.modifiers = modifiers
+ data.name = name
+ data.postfixToken = postfixToken
+ data.typeNode = typeNode
+ data.initializer = initializer
+ return f.NewNode(SyntaxKindPropertyDeclaration, data)
+}
+
+func (node *PropertyDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.postfixToken) || visit(v, node.typeNode) || visit(v, node.initializer)
+}
+
+func isPropertyDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindPropertyDeclaration
+}
+
+// SemicolonClassElement
+
+type SemicolonClassElement struct {
+ NodeBase
+ DeclarationBase
+ ClassElementBase
+}
+
+func (f *NodeFactory) NewSemicolonClassElement() *Node {
+ return f.NewNode(SyntaxKindSemicolonClassElement, &SemicolonClassElement{})
+}
+
+// ClassStaticBlockDeclaration
+
+type ClassStaticBlockDeclaration struct {
+ NodeBase
+ DeclarationBase
+ ModifiersBase
+ LocalsContainerBase
+ ClassElementBase
+ body *Node
+}
+
+func (f *NodeFactory) NewClassStaticBlockDeclaration(modifiers *Node, body *Node) *Node {
+ data := &ClassStaticBlockDeclaration{}
+ data.modifiers = modifiers
+ data.body = body
+ return f.NewNode(SyntaxKindClassStaticBlockDeclaration, data)
+}
+
+func (node *ClassStaticBlockDeclaration) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.body)
+}
+
+func isClassStaticBlockDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindClassStaticBlockDeclaration
+}
+
+// TypeParameterList
+
+type TypeParameterList struct {
+ NodeBase
+ parameters []*Node
+}
+
+func (f *NodeFactory) NewTypeParameterList(parameters []*Node) *Node {
+ data := &TypeParameterList{}
+ data.parameters = parameters
+ return f.NewNode(SyntaxKindTypeParameterList, data)
+}
+
+func (node *TypeParameterList) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.parameters)
+}
+
+// ExpressionBase
+
+type ExpressionBase struct {
+ NodeBase
+}
+
+// OmittedExpression
+
+type OmittedExpression struct {
+ ExpressionBase
+}
+
+func (f *NodeFactory) NewOmittedExpression() *Node {
+ return f.NewNode(SyntaxKindOmittedExpression, &OmittedExpression{})
+}
+
+// KeywordExpression
+
+type KeywordExpression struct {
+ ExpressionBase
+ FlowNodeBase // For 'this' and 'super' expressions
+}
+
+func (f *NodeFactory) NewKeywordExpression(kind SyntaxKind) *Node {
+ return f.NewNode(kind, &KeywordExpression{})
+}
+
+// LiteralLikeBase
+
+type LiteralLikeBase struct {
+ text string
+}
+
+// StringLiteral
+
+type StringLiteral struct {
+ ExpressionBase
+ LiteralLikeBase
+}
+
+func (f *NodeFactory) NewStringLiteral(text string) *Node {
+ data := &StringLiteral{}
+ data.text = text
+ return f.NewNode(SyntaxKindStringLiteral, data)
+}
+
+func isStringLiteral(node *Node) bool {
+ return node.kind == SyntaxKindStringLiteral
+}
+
+// NumericLiteral
+
+type NumericLiteral struct {
+ ExpressionBase
+ LiteralLikeBase
+}
+
+func (f *NodeFactory) NewNumericLiteral(text string) *Node {
+ data := &NumericLiteral{}
+ data.text = text
+ return f.NewNode(SyntaxKindNumericLiteral, data)
+}
+
+// BigintLiteral
+
+type BigintLiteral struct {
+ ExpressionBase
+ LiteralLikeBase
+}
+
+func (f *NodeFactory) NewBigintLiteral(text string) *Node {
+ data := &BigintLiteral{}
+ data.text = text
+ return f.NewNode(SyntaxKindBigintLiteral, data)
+}
+
+// RegularExpressionLiteral
+
+type RegularExpressionLiteral struct {
+ ExpressionBase
+ LiteralLikeBase
+}
+
+func (f *NodeFactory) NewRegularExpressionLiteral(text string) *Node {
+ data := &RegularExpressionLiteral{}
+ data.text = text
+ return f.NewNode(SyntaxKindRegularExpressionLiteral, data)
+}
+
+// NoSubstitutionTemplateLiteral
+
+type NoSubstitutionTemplateLiteral struct {
+ ExpressionBase
+ TemplateLiteralLikeBase
+}
+
+func (f *NodeFactory) NewNoSubstitutionTemplateLiteral(text string) *Node {
+ data := &NoSubstitutionTemplateLiteral{}
+ data.text = text
+ return f.NewNode(SyntaxKindNoSubstitutionTemplateLiteral, data)
+}
+
+// BinaryExpression
+
+type BinaryExpression struct {
+ ExpressionBase
+ DeclarationBase
+ left *Node
+ operatorToken *Node
+ right *Node
+}
+
+func (f *NodeFactory) NewBinaryExpression(left *Node, operatorToken *Node, right *Node) *Node {
+ data := &BinaryExpression{}
+ data.left = left
+ data.operatorToken = operatorToken
+ data.right = right
+ return f.NewNode(SyntaxKindBinaryExpression, data)
+}
+
+func (node *BinaryExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.left) || visit(v, node.operatorToken) || visit(v, node.right)
+}
+
+// PrefixUnaryExpression
+
+type PrefixUnaryExpression struct {
+ ExpressionBase
+ operator SyntaxKind
+ operand *Node
+}
+
+func (f *NodeFactory) NewPrefixUnaryExpression(operator SyntaxKind, operand *Node) *Node {
+ data := &PrefixUnaryExpression{}
+ data.operator = operator
+ data.operand = operand
+ return f.NewNode(SyntaxKindPrefixUnaryExpression, data)
+}
+
+func (node *PrefixUnaryExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.operand)
+}
+
+func isPrefixUnaryExpression(node *Node) bool {
+ return node.kind == SyntaxKindPrefixUnaryExpression
+}
+
+// PostfixUnaryExpression
+
+type PostfixUnaryExpression struct {
+ ExpressionBase
+ operand *Node
+ operator SyntaxKind
+}
+
+func (f *NodeFactory) NewPostfixUnaryExpression(operand *Node, operator SyntaxKind) *Node {
+ data := &PostfixUnaryExpression{}
+ data.operand = operand
+ data.operator = operator
+ return f.NewNode(SyntaxKindPostfixUnaryExpression, data)
+}
+
+func (node *PostfixUnaryExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.operand)
+}
+
+// YieldExpression
+
+type YieldExpression struct {
+ ExpressionBase
+ asteriskToken *Node
+ expression *Node // Optional
+}
+
+func (f *NodeFactory) NewYieldExpression(asteriskToken *Node, expression *Node) *Node {
+ data := &YieldExpression{}
+ data.asteriskToken = asteriskToken
+ data.expression = expression
+ return f.NewNode(SyntaxKindYieldExpression, data)
+}
+
+func (node *YieldExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.asteriskToken) || visit(v, node.expression)
+}
+
+// ArrowFunction
+
+type ArrowFunction struct {
+ ExpressionBase
+ DeclarationBase
+ ModifiersBase
+ FunctionLikeWithBodyBase
+ FlowNodeBase
+ equalsGreaterThanToken *Node
+}
+
+func (f *NodeFactory) NewArrowFunction(modifiers *Node, typeParameters *Node, parameters []*Node, returnType *Node, equalsGreaterThanToken *Node, body *Node) *Node {
+ data := &ArrowFunction{}
+ data.modifiers = modifiers
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ data.equalsGreaterThanToken = equalsGreaterThanToken
+ data.body = body
+ return f.NewNode(SyntaxKindArrowFunction, data)
+}
+
+func (node *ArrowFunction) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.typeParameters) || visitNodes(v, node.parameters) ||
+ visit(v, node.returnType) || visit(v, node.equalsGreaterThanToken) || visit(v, node.body)
+}
+
+func (node *ArrowFunction) Name() *DeclarationName {
+ return nil
+}
+
+func isArrowFunction(node *Node) bool {
+ return node.kind == SyntaxKindArrowFunction
+}
+
+// FunctionExpression
+
+type FunctionExpression struct {
+ ExpressionBase
+ DeclarationBase
+ ModifiersBase
+ FunctionLikeWithBodyBase
+ FlowNodeBase
+ name *Node // Optional
+ returnFlowNode *FlowNode
+}
+
+func (f *NodeFactory) NewFunctionExpression(modifiers *Node, asteriskToken *Node, name *Node, typeParameters *Node, parameters []*Node, returnType *Node, body *Node) *Node {
+ data := &FunctionExpression{}
+ data.modifiers = modifiers
+ data.asteriskToken = asteriskToken
+ data.name = name
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ data.body = body
+ return f.NewNode(SyntaxKindFunctionExpression, data)
+}
+
+func (node *FunctionExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.asteriskToken) || visit(v, node.name) || visit(v, node.typeParameters) ||
+ visitNodes(v, node.parameters) || visit(v, node.returnType) || visit(v, node.body)
+}
+
+func (node *FunctionExpression) Name() *DeclarationName {
+ return node.name
+}
+
+func isFunctionExpression(node *Node) bool {
+ return node.kind == SyntaxKindFunctionExpression
+}
+
+// AsExpression
+
+type AsExpression struct {
+ ExpressionBase
+ expression *Node
+ typeNode *Node
+}
+
+func (f *NodeFactory) NewAsExpression(expression *Node, typeNode *Node) *Node {
+ data := &AsExpression{}
+ data.expression = expression
+ data.typeNode = typeNode
+ return f.NewNode(SyntaxKindAsExpression, data)
+}
+
+func (node *AsExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.typeNode)
+}
+
+// SatisfiesExpression
+
+type SatisfiesExpression struct {
+ ExpressionBase
+ expression *Node
+ typeNode *Node
+}
+
+func (f *NodeFactory) NewSatisfiesExpression(expression *Node, typeNode *Node) *Node {
+ data := &SatisfiesExpression{}
+ data.expression = expression
+ data.typeNode = typeNode
+ return f.NewNode(SyntaxKindSatisfiesExpression, data)
+}
+
+func (node *SatisfiesExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.typeNode)
+}
+
+// ConditionalExpression
+
+type ConditionalExpression struct {
+ ExpressionBase
+ condition *Node
+ questionToken *Node
+ whenTrue *Node
+ colonToken *Node
+ whenFalse *Node
+}
+
+func (f *NodeFactory) NewConditionalExpression(condition *Node, questionToken *Node, whenTrue *Node, colonToken *Node, whenFalse *Node) *Node {
+ data := &ConditionalExpression{}
+ data.condition = condition
+ data.questionToken = questionToken
+ data.whenTrue = whenTrue
+ data.colonToken = colonToken
+ data.whenFalse = whenFalse
+ return f.NewNode(SyntaxKindConditionalExpression, data)
+}
+
+func (node *ConditionalExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.condition) || visit(v, node.questionToken) || visit(v, node.whenTrue) ||
+ visit(v, node.colonToken) || visit(v, node.whenFalse)
+}
+
+// PropertyAccessExpression
+
+type PropertyAccessExpression struct {
+ ExpressionBase
+ FlowNodeBase
+ expression *Node
+ questionDotToken *Node
+ name *Node
+}
+
+func (f *NodeFactory) NewPropertyAccessExpression(expression *Node, questionDotToken *Node, name *Node, flags NodeFlags) *Node {
+ data := &PropertyAccessExpression{}
+ data.expression = expression
+ data.questionDotToken = questionDotToken
+ data.name = name
+ node := f.NewNode(SyntaxKindPropertyAccessExpression, data)
+ node.flags |= flags & NodeFlagsOptionalChain
+ return node
+}
+
+func (node *PropertyAccessExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.questionDotToken) || visit(v, node.name)
+}
+
+func (node *PropertyAccessExpression) Name() *DeclarationName { return node.name }
+
+func isPropertyAccessExpression(node *Node) bool {
+ return node.kind == SyntaxKindPropertyAccessExpression
+}
+
+// ElementAccessExpression
+
+type ElementAccessExpression struct {
+ ExpressionBase
+ FlowNodeBase
+ expression *Node
+ questionDotToken *Node
+ argumentExpression *Node
+}
+
+func (f *NodeFactory) NewElementAccessExpression(expression *Node, questionDotToken *Node, argumentExpression *Node, flags NodeFlags) *Node {
+ data := &ElementAccessExpression{}
+ data.expression = expression
+ data.questionDotToken = questionDotToken
+ data.argumentExpression = argumentExpression
+ node := f.NewNode(SyntaxKindElementAccessExpression, data)
+ node.flags |= flags & NodeFlagsOptionalChain
+ return node
+}
+
+func (node *ElementAccessExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.questionDotToken) || visit(v, node.argumentExpression)
+}
+
+func isElementAccessExpression(node *Node) bool {
+ return node.kind == SyntaxKindElementAccessExpression
+}
+
+// CallExpression
+
+type CallExpression struct {
+ ExpressionBase
+ expression *Node
+ questionDotToken *Node
+ typeArguments *Node
+ arguments []*Node
+}
+
+func (f *NodeFactory) NewCallExpression(expression *Node, questionDotToken *Node, typeArguments *Node, arguments []*Node, flags NodeFlags) *Node {
+ data := &CallExpression{}
+ data.expression = expression
+ data.questionDotToken = questionDotToken
+ data.typeArguments = typeArguments
+ data.arguments = arguments
+ node := f.NewNode(SyntaxKindCallExpression, data)
+ node.flags |= flags & NodeFlagsOptionalChain
+ return node
+}
+
+func (node *CallExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.questionDotToken) || visit(v, node.typeArguments) || visitNodes(v, node.arguments)
+}
+
+func isCallExpression(node *Node) bool {
+ return node.kind == SyntaxKindCallExpression
+}
+
+// NewExpression
+
+type NewExpression struct {
+ ExpressionBase
+ expression *Node
+ typeArguments *Node
+ arguments []*Node
+}
+
+func (f *NodeFactory) NewNewExpression(expression *Node, typeArguments *Node, arguments []*Node) *Node {
+ data := &NewExpression{}
+ data.expression = expression
+ data.typeArguments = typeArguments
+ data.arguments = arguments
+ return f.NewNode(SyntaxKindNewExpression, data)
+}
+
+func (node *NewExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.typeArguments) || visitNodes(v, node.arguments)
+}
+
+// MetaProperty
+
+type MetaProperty struct {
+ ExpressionBase
+ FlowNodeBase
+ keywordToken SyntaxKind
+ name *Node
+}
+
+func (f *NodeFactory) NewMetaProperty(keywordToken SyntaxKind, name *Node) *Node {
+ data := &MetaProperty{}
+ data.keywordToken = keywordToken
+ data.name = name
+ return f.NewNode(SyntaxKindNewExpression, data)
+}
+
+func (node *MetaProperty) ForEachChild(v Visitor) bool {
+ return visit(v, node.name)
+}
+
+func isMetaProperty(node *Node) bool {
+ return node.kind == SyntaxKindMetaProperty
+}
+
+// NonNullExpression
+
+type NonNullExpression struct {
+ ExpressionBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewNonNullExpression(expression *Node) *Node {
+ data := &NonNullExpression{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindNewExpression, data)
+}
+
+func (node *NonNullExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+// SpreadElement
+
+type SpreadElement struct {
+ ExpressionBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewSpreadElement(expression *Node) *Node {
+ data := &SpreadElement{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindSpreadElement, data)
+}
+
+func (node *SpreadElement) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+// TemplateExpression
+
+type TemplateExpression struct {
+ ExpressionBase
+ head *Node
+ templateSpans []*Node
+}
+
+func (f *NodeFactory) NewTemplateExpression(head *Node, templateSpans []*Node) *Node {
+ data := &TemplateExpression{}
+ data.head = head
+ data.templateSpans = templateSpans
+ return f.NewNode(SyntaxKindTemplateExpression, data)
+}
+
+func (node *TemplateExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.head) || visitNodes(v, node.templateSpans)
+}
+
+// TemplateLiteralTypeSpan
+
+type TemplateSpan struct {
+ NodeBase
+ expression *Node
+ literal *Node
+}
+
+func (f *NodeFactory) NewTemplateSpan(expression *Node, literal *Node) *Node {
+ data := &TemplateSpan{}
+ data.expression = expression
+ data.literal = literal
+ return f.NewNode(SyntaxKindTemplateSpan, data)
+}
+
+func (node *TemplateSpan) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.literal)
+}
+
+// TaggedTemplateExpression
+
+type TaggedTemplateExpression struct {
+ ExpressionBase
+ tag *Node
+ questionDotToken *Node // For error reporting purposes only
+ typeArguments *Node
+ template *Node
+}
+
+func (f *NodeFactory) NewTaggedTemplateExpression(tag *Node, questionDotToken *Node, typeArguments *Node, template *Node, flags NodeFlags) *Node {
+ data := &TaggedTemplateExpression{}
+ data.tag = tag
+ data.questionDotToken = questionDotToken
+ data.typeArguments = typeArguments
+ data.template = template
+ node := f.NewNode(SyntaxKindTemplateExpression, data)
+ node.flags |= flags & NodeFlagsOptionalChain
+ return node
+}
+
+func (node *TaggedTemplateExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.tag) || visit(v, node.questionDotToken) || visit(v, node.typeArguments) || visit(v, node.template)
+}
+
+// ParenthesizedExpression
+
+type ParenthesizedExpression struct {
+ ExpressionBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewParenthesizedExpression(expression *Node) *Node {
+ data := &ParenthesizedExpression{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindParenthesizedExpression, data)
+}
+
+func (node *ParenthesizedExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+func isParenthesizedExpression(node *Node) bool {
+ return node.kind == SyntaxKindParenthesizedExpression
+}
+
+// ArrayLiteralExpression
+
+type ArrayLiteralExpression struct {
+ ExpressionBase
+ elements []*Node
+ multiLine bool
+}
+
+func (f *NodeFactory) NewArrayLiteralExpression(elements []*Node, multiLine bool) *Node {
+ data := &ArrayLiteralExpression{}
+ data.elements = elements
+ data.multiLine = multiLine
+ return f.NewNode(SyntaxKindArrayLiteralExpression, data)
+}
+
+func (node *ArrayLiteralExpression) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.elements)
+}
+
+// ObjectLiteralExpression
+
+type ObjectLiteralExpression struct {
+ ExpressionBase
+ DeclarationBase
+ properties []*Node
+ multiLine bool
+}
+
+func (f *NodeFactory) NewObjectLiteralExpression(properties []*Node, multiLine bool) *Node {
+ data := &ObjectLiteralExpression{}
+ data.properties = properties
+ data.multiLine = multiLine
+ return f.NewNode(SyntaxKindObjectLiteralExpression, data)
+
+}
+
+func (node *ObjectLiteralExpression) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.properties)
+}
+
+func isObjectLiteralExpression(node *Node) bool {
+ return node.kind == SyntaxKindObjectLiteralExpression
+}
+
+// ObjectLiteralElementBase
+
+type ObjectLiteralElementBase struct{}
+
+// SpreadAssignment
+
+type SpreadAssignment struct {
+ NodeBase
+ ObjectLiteralElementBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewSpreadAssignment(expression *Node) *Node {
+ data := &SpreadAssignment{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindSpreadAssignment, data)
+}
+
+func (node *SpreadAssignment) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+// PropertyAssignment
+
+type PropertyAssignment struct {
+ NodeBase
+ NamedMemberBase
+ ObjectLiteralElementBase
+ initializer *Node
+}
+
+func (f *NodeFactory) NewPropertyAssignment(modifiers *Node, name *Node, postfixToken *Node, initializer *Node) *Node {
+ data := &PropertyAssignment{}
+ data.modifiers = modifiers
+ data.name = name
+ data.postfixToken = postfixToken
+ data.initializer = initializer
+ return f.NewNode(SyntaxKindPropertyAssignment, data)
+}
+
+func (node *PropertyAssignment) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.postfixToken) || visit(v, node.initializer)
+}
+
+func isPropertyAssignment(node *Node) bool {
+ return node.kind == SyntaxKindPropertyAssignment
+}
+
+// ShorthandPropertyAssignment
+
+type ShorthandPropertyAssignment struct {
+ NodeBase
+ NamedMemberBase
+ ObjectLiteralElementBase
+ objectAssignmentInitializer *Node // Optional
+}
+
+func (f *NodeFactory) NewShorthandPropertyAssignment(modifiers *Node, name *Node, postfixToken *Node, objectAssignmentInitializer *Node) *Node {
+ data := &ShorthandPropertyAssignment{}
+ data.modifiers = modifiers
+ data.name = name
+ data.postfixToken = postfixToken
+ data.objectAssignmentInitializer = objectAssignmentInitializer
+ return f.NewNode(SyntaxKindShorthandPropertyAssignment, data)
+}
+
+func (node *ShorthandPropertyAssignment) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.name) || visit(v, node.postfixToken) || visit(v, node.objectAssignmentInitializer)
+}
+
+func isShorthandPropertyAssignment(node *Node) bool {
+ return node.kind == SyntaxKindShorthandPropertyAssignment
+}
+
+// DeleteExpression
+
+type DeleteExpression struct {
+ ExpressionBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewDeleteExpression(expression *Node) *Node {
+ data := &DeleteExpression{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindDeleteExpression, data)
+
+}
+
+func (node *DeleteExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+// TypeOfExpression
+
+type TypeOfExpression struct {
+ ExpressionBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewTypeOfExpression(expression *Node) *Node {
+ data := &TypeOfExpression{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindTypeOfExpression, data)
+}
+
+func (node *TypeOfExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+func isTypeOfExpression(node *Node) bool {
+ return node.kind == SyntaxKindTypeOfExpression
+}
+
+// VoidExpression
+
+type VoidExpression struct {
+ ExpressionBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewVoidExpression(expression *Node) *Node {
+ data := &VoidExpression{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindVoidExpression, data)
+}
+
+func (node *VoidExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+// AwaitExpression
+
+type AwaitExpression struct {
+ ExpressionBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewAwaitExpression(expression *Node) *Node {
+ data := &AwaitExpression{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindAwaitExpression, data)
+}
+
+func (node *AwaitExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+// TypeAssertion
+
+type TypeAssertion struct {
+ ExpressionBase
+ typeNode *Node
+ expression *Node
+}
+
+func (f *NodeFactory) NewTypeAssertion(typeNode *Node, expression *Node) *Node {
+ data := &TypeAssertion{}
+ data.typeNode = typeNode
+ data.expression = expression
+ return f.NewNode(SyntaxKindTypeAssertionExpression, data)
+}
+
+func (node *TypeAssertion) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeNode) || visit(v, node.expression)
+}
+
+// TypeNodeBase
+
+type TypeNodeBase struct {
+ NodeBase
+}
+
+// KeywordTypeNode
+
+type KeywordTypeNode struct {
+ TypeNodeBase
+}
+
+func (f *NodeFactory) NewKeywordTypeNode(kind SyntaxKind) *Node {
+ return f.NewNode(kind, &KeywordTypeNode{})
+}
+
+// UnionOrIntersectionTypeBase
+
+type UnionOrIntersectionTypeNodeBase struct {
+ TypeNodeBase
+ types []*Node
+}
+
+func (node *UnionOrIntersectionTypeNodeBase) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.types)
+}
+
+// UnionTypeNode
+
+type UnionTypeNode struct {
+ UnionOrIntersectionTypeNodeBase
+}
+
+func (f *NodeFactory) NewUnionTypeNode(types []*Node) *Node {
+ data := &UnionTypeNode{}
+ data.types = types
+ return f.NewNode(SyntaxKindUnionType, data)
+}
+
+// IntersectionTypeNode
+
+type IntersectionTypeNode struct {
+ UnionOrIntersectionTypeNodeBase
+}
+
+func (f *NodeFactory) NewIntersectionTypeNode(types []*Node) *Node {
+ data := &IntersectionTypeNode{}
+ data.types = types
+ return f.NewNode(SyntaxKindIntersectionType, data)
+}
+
+// ConditionalTypeNode
+
+type ConditionalTypeNode struct {
+ TypeNodeBase
+ LocalsContainerBase
+ checkType *Node
+ extendsType *Node
+ trueType *Node
+ falseType *Node
+}
+
+func (f *NodeFactory) NewConditionalTypeNode(checkType *Node, extendsType *Node, trueType *Node, falseType *Node) *Node {
+ data := &ConditionalTypeNode{}
+ data.checkType = checkType
+ data.extendsType = extendsType
+ data.trueType = trueType
+ data.falseType = falseType
+ return f.NewNode(SyntaxKindConditionalType, data)
+}
+
+func (node *ConditionalTypeNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.checkType) || visit(v, node.extendsType) || visit(v, node.trueType) || visit(v, node.falseType)
+}
+
+func isConditionalTypeNode(node *Node) bool {
+ return node.kind == SyntaxKindConditionalType
+}
+
+// TypeOperatorNode
+
+type TypeOperatorNode struct {
+ TypeNodeBase
+ operator SyntaxKind // SyntaxKindKeyOfKeyword | SyntaxKindUniqueKeyword | SyntaxKindReadonlyKeyword
+ typeNode *Node
+}
+
+func (f *NodeFactory) NewTypeOperatorNode(operator SyntaxKind, typeNode *Node) *Node {
+ data := &TypeOperatorNode{}
+ data.operator = operator
+ data.typeNode = typeNode
+ return f.NewNode(SyntaxKindTypeOperator, data)
+}
+
+func (node *TypeOperatorNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeNode)
+}
+
+func isTypeOperatorNode(node *Node) bool {
+ return node.kind == SyntaxKindTypeOperator
+}
+
+// InferTypeNode
+
+type InferTypeNode struct {
+ TypeNodeBase
+ typeParameter *Node
+}
+
+func (f *NodeFactory) NewInferTypeNode(typeParameter *Node) *Node {
+ data := &InferTypeNode{}
+ data.typeParameter = typeParameter
+ return f.NewNode(SyntaxKindInferType, data)
+}
+
+func (node *InferTypeNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeParameter)
+}
+
+// ArrayTypeNode
+
+type ArrayTypeNode struct {
+ TypeNodeBase
+ elementType *Node
+}
+
+func (f *NodeFactory) NewArrayTypeNode(elementType *Node) *Node {
+ data := &ArrayTypeNode{}
+ data.elementType = elementType
+ return f.NewNode(SyntaxKindArrayType, data)
+}
+
+func (node *ArrayTypeNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.elementType)
+}
+
+// IndexedAccessTypeNode
+
+type IndexedAccessTypeNode struct {
+ TypeNodeBase
+ objectType *Node
+ indexType *Node
+}
+
+func (f *NodeFactory) NewIndexedAccessTypeNode(objectType *Node, indexType *Node) *Node {
+ data := &IndexedAccessTypeNode{}
+ data.objectType = objectType
+ data.indexType = indexType
+ return f.NewNode(SyntaxKindIndexedAccessType, data)
+}
+
+func (node *IndexedAccessTypeNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.objectType) || visit(v, node.indexType)
+}
+
+// TypeArgumentList
+
+type TypeArgumentList struct {
+ NodeBase
+ arguments []*Node
+}
+
+func (f *NodeFactory) NewTypeArgumentList(arguments []*Node) *Node {
+ data := &TypeArgumentList{}
+ data.arguments = arguments
+ return f.NewNode(SyntaxKindTypeArgumentList, data)
+}
+
+func (node *TypeArgumentList) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.arguments)
+}
+
+// TypeReferenceNode
+
+type TypeReferenceNode struct {
+ TypeNodeBase
+ typeName *Node
+ typeArguments *Node
+}
+
+func (f *NodeFactory) NewTypeReferenceNode(typeName *Node, typeArguments *Node) *Node {
+ data := &TypeReferenceNode{}
+ data.typeName = typeName
+ data.typeArguments = typeArguments
+ return f.NewNode(SyntaxKindTypeReference, data)
+}
+
+func (node *TypeReferenceNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeName) || visit(v, node.typeArguments)
+}
+
+func isTypeReferenceNode(node *Node) bool {
+ return node.kind == SyntaxKindTypeReference
+}
+
+// ExpressionWithTypeArguments
+
+type ExpressionWithTypeArguments struct {
+ ExpressionBase
+ expression *Node
+ typeArguments *Node
+}
+
+func (f *NodeFactory) NewExpressionWithTypeArguments(expression *Node, typeArguments *Node) *Node {
+ data := &ExpressionWithTypeArguments{}
+ data.expression = expression
+ data.typeArguments = typeArguments
+ return f.NewNode(SyntaxKindExpressionWithTypeArguments, data)
+}
+
+func (node *ExpressionWithTypeArguments) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression) || visit(v, node.typeArguments)
+}
+
+// LiteralTypeNode
+
+type LiteralTypeNode struct {
+ TypeNodeBase
+ literal *Node // KeywordExpression | LiteralExpression | PrefixUnaryExpression
+}
+
+func (f *NodeFactory) NewLiteralTypeNode(literal *Node) *Node {
+ data := &LiteralTypeNode{}
+ data.literal = literal
+ return f.NewNode(SyntaxKindLiteralType, data)
+}
+
+func (node *LiteralTypeNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.literal)
+}
+
+func isLiteralTypeNode(node *Node) bool {
+ return node.kind == SyntaxKindLiteralType
+}
+
+// ThisTypeNode
+
+type ThisTypeNode struct {
+ TypeNodeBase
+}
+
+func (f *NodeFactory) NewThisTypeNode() *Node {
+ return f.NewNode(SyntaxKindThisType, &ThisTypeNode{})
+}
+
+// TypePredicateNode
+
+type TypePredicateNode struct {
+ TypeNodeBase
+ assertsModifier *Node // Optional
+ parameterName *Node // Identifier | ThisTypeNode
+ typeNode *Node // Optional
+}
+
+func (f *NodeFactory) NewTypePredicateNode(assertsModifier *Node, parameterName *Node, typeNode *Node) *Node {
+ data := &TypePredicateNode{}
+ data.assertsModifier = assertsModifier
+ data.parameterName = parameterName
+ data.typeNode = typeNode
+ return f.NewNode(SyntaxKindTypePredicate, data)
+}
+
+func (node *TypePredicateNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.assertsModifier) || visit(v, node.parameterName) || visit(v, node.typeNode)
+}
+
+// ImportTypeNode
+
+type ImportTypeNode struct {
+ TypeNodeBase
+ isTypeOf bool
+ argument *Node
+ attributes *Node // Optional
+ qualifier *Node // Optional
+ typeArguments *Node // Optional
+}
+
+func (f *NodeFactory) NewImportTypeNode(isTypeOf bool, argument *Node, attributes *Node, qualifier *Node, typeArguments *Node) *Node {
+ data := &ImportTypeNode{}
+ data.isTypeOf = isTypeOf
+ data.argument = argument
+ data.attributes = attributes
+ data.qualifier = qualifier
+ data.typeArguments = typeArguments
+ return f.NewNode(SyntaxKindImportType, data)
+}
+
+func (node *ImportTypeNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.argument) || visit(v, node.attributes) || visit(v, node.qualifier) || visit(v, node.typeArguments)
+}
+
+func isImportTypeNode(node *Node) bool {
+ return node.kind == SyntaxKindImportType
+}
+
+// ImportAttribute
+
+type ImportAttribute struct {
+ NodeBase
+ name *Node
+ value *Node
+}
+
+func (f *NodeFactory) NewImportAttribute(name *Node, value *Node) *Node {
+ data := &ImportAttribute{}
+ data.name = name
+ data.value = value
+ return f.NewNode(SyntaxKindImportAttribute, data)
+}
+
+func (node *ImportAttribute) ForEachChild(v Visitor) bool {
+ return visit(v, node.name) || visit(v, node.value)
+}
+
+// ImportAttributes
+
+type ImportAttributes struct {
+ NodeBase
+ token SyntaxKind
+ attributes []*Node
+ multiLine bool
+}
+
+func (f *NodeFactory) NewImportAttributes(token SyntaxKind, attributes []*Node, multiLine bool) *Node {
+ data := &ImportAttributes{}
+ data.token = token
+ data.attributes = attributes
+ data.multiLine = multiLine
+ return f.NewNode(SyntaxKindImportAttributes, data)
+}
+
+func (node *ImportAttributes) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.attributes)
+}
+
+// TypeQueryNode
+
+type TypeQueryNode struct {
+ TypeNodeBase
+ exprName *Node
+ typeArguments *Node
+}
+
+func (f *NodeFactory) NewTypeQueryNode(exprName *Node, typeArguments *Node) *Node {
+ data := &TypeQueryNode{}
+ data.exprName = exprName
+ data.typeArguments = typeArguments
+ return f.NewNode(SyntaxKindTypeQuery, data)
+}
+
+func (node *TypeQueryNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.exprName) || visit(v, node.typeArguments)
+}
+
+func isTypeQueryNode(node *Node) bool {
+ return node.kind == SyntaxKindTypeQuery
+}
+
+// MappedTypeNode
+
+type MappedTypeNode struct {
+ TypeNodeBase
+ DeclarationBase
+ LocalsContainerBase
+ readonlyToken *Node // Optional
+ typeParameter *Node
+ nameType *Node // Optional
+ questionToken *Node // Optional
+ typeNode *Node // Optional (error if missing)
+ members []*Node // Used only to produce grammar errors
+}
+
+func (f *NodeFactory) NewMappedTypeNode(readonlyToken *Node, typeParameter *Node, nameType *Node, questionToken *Node, typeNode *Node, members []*Node) *Node {
+ data := &MappedTypeNode{}
+ data.readonlyToken = readonlyToken
+ data.typeParameter = typeParameter
+ data.nameType = nameType
+ data.questionToken = questionToken
+ data.typeNode = typeNode
+ data.members = members
+ return f.NewNode(SyntaxKindMappedType, data)
+}
+
+func (node *MappedTypeNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.readonlyToken) || visit(v, node.typeParameter) || visit(v, node.nameType) ||
+ visit(v, node.questionToken) || visit(v, node.typeNode) || visitNodes(v, node.members)
+}
+
+// TypeLiteralNode
+
+type TypeLiteralNode struct {
+ TypeNodeBase
+ DeclarationBase
+ members []*TypeElement
+}
+
+func (f *NodeFactory) NewTypeLiteralNode(members []*TypeElement) *Node {
+ data := &TypeLiteralNode{}
+ data.members = members
+ return f.NewNode(SyntaxKindTypeLiteral, data)
+}
+
+func (node *TypeLiteralNode) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.members)
+}
+
+// TupleTypeNode
+
+type TupleTypeNode struct {
+ TypeNodeBase
+ elements []*TypeNode
+}
+
+func (f *NodeFactory) NewTupleTypeNode(elements []*TypeNode) *Node {
+ data := &TupleTypeNode{}
+ data.elements = elements
+ return f.NewNode(SyntaxKindTupleType, data)
+}
+
+func (node *TupleTypeNode) Kind() SyntaxKind {
+ return SyntaxKindTupleType
+}
+
+func (node *TupleTypeNode) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.elements)
+}
+
+// NamedTupleTypeMember
+
+type NamedTupleMember struct {
+ TypeNodeBase
+ DeclarationBase
+ dotDotDotToken *Node
+ name *Node
+ questionToken *Node
+ typeNode *Node
+}
+
+func (f *NodeFactory) NewNamedTupleTypeMember(dotDotDotToken *Node, name *Node, questionToken *Node, typeNode *Node) *Node {
+ data := &NamedTupleMember{}
+ data.dotDotDotToken = dotDotDotToken
+ data.name = name
+ data.questionToken = questionToken
+ data.typeNode = typeNode
+ return f.NewNode(SyntaxKindNamedTupleMember, data)
+}
+
+func (node *NamedTupleMember) ForEachChild(v Visitor) bool {
+ return visit(v, node.dotDotDotToken) || visit(v, node.name) || visit(v, node.questionToken) || visit(v, node.typeNode)
+}
+
+// OptionalTypeNode
+
+type OptionalTypeNode struct {
+ TypeNodeBase
+ typeNode *TypeNode
+}
+
+func (f *NodeFactory) NewOptionalTypeNode(typeNode *TypeNode) *Node {
+ data := &OptionalTypeNode{}
+ data.typeNode = typeNode
+ return f.NewNode(SyntaxKindOptionalType, data)
+}
+
+func (node *OptionalTypeNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeNode)
+}
+
+// RestTypeNode
+
+type RestTypeNode struct {
+ TypeNodeBase
+ typeNode *TypeNode
+}
+
+func (f *NodeFactory) NewRestTypeNode(typeNode *TypeNode) *Node {
+ data := &RestTypeNode{}
+ data.typeNode = typeNode
+ return f.NewNode(SyntaxKindRestType, data)
+}
+
+func (node *RestTypeNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeNode)
+}
+
+// ParenthesizedTypeNode
+
+type ParenthesizedTypeNode struct {
+ TypeNodeBase
+ typeNode *TypeNode
+}
+
+func (f *NodeFactory) NewParenthesizedTypeNode(typeNode *TypeNode) *Node {
+ data := &ParenthesizedTypeNode{}
+ data.typeNode = typeNode
+ return f.NewNode(SyntaxKindParenthesizedType, data)
+}
+
+func (node *ParenthesizedTypeNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeNode)
+}
+
+func isParenthesizedTypeNode(node *Node) bool {
+ return node.kind == SyntaxKindParenthesizedType
+}
+
+// FunctionOrConstructorTypeNodeBase
+
+type FunctionOrConstructorTypeNodeBase struct {
+ TypeNodeBase
+ DeclarationBase
+ ModifiersBase
+ FunctionLikeBase
+}
+
+func (node *FunctionOrConstructorTypeNodeBase) ForEachChild(v Visitor) bool {
+ return visit(v, node.modifiers) || visit(v, node.typeParameters) || visitNodes(v, node.parameters) || visit(v, node.returnType)
+}
+
+// FunctionTypeNode
+
+type FunctionTypeNode struct {
+ FunctionOrConstructorTypeNodeBase
+}
+
+func (f *NodeFactory) NewFunctionTypeNode(typeParameters *Node, parameters []*Node, returnType *Node) *Node {
+ data := &FunctionTypeNode{}
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ return f.NewNode(SyntaxKindFunctionType, data)
+}
+
+func isFunctionTypeNode(node *Node) bool {
+ return node.kind == SyntaxKindFunctionType
+}
+
+// ConstructorTypeNode
+
+type ConstructorTypeNode struct {
+ FunctionOrConstructorTypeNodeBase
+}
+
+func (f *NodeFactory) NewConstructorTypeNode(modifiers *Node, typeParameters *Node, parameters []*Node, returnType *Node) *Node {
+ data := &ConstructorTypeNode{}
+ data.modifiers = modifiers
+ data.typeParameters = typeParameters
+ data.parameters = parameters
+ data.returnType = returnType
+ return f.NewNode(SyntaxKindConstructorType, data)
+}
+
+// TemplateLiteralLikeBase
+
+type TemplateLiteralLikeBase struct {
+ LiteralLikeBase
+ rawText string
+ templateFlags TokenFlags
+}
+
+// TemplateHead
+
+type TemplateHead struct {
+ NodeBase
+ TemplateLiteralLikeBase
+}
+
+func (f *NodeFactory) NewTemplateHead(text string, rawText string, templateFlags TokenFlags) *Node {
+ data := &TemplateHead{}
+ data.text = text
+ data.rawText = rawText
+ data.templateFlags = templateFlags
+ return f.NewNode(SyntaxKindTemplateHead, data)
+}
+
+// TemplateMiddle
+
+type TemplateMiddle struct {
+ NodeBase
+ TemplateLiteralLikeBase
+}
+
+func (f *NodeFactory) NewTemplateMiddle(text string, rawText string, templateFlags TokenFlags) *Node {
+ data := &TemplateMiddle{}
+ data.text = text
+ data.rawText = rawText
+ data.templateFlags = templateFlags
+ return f.NewNode(SyntaxKindTemplateMiddle, data)
+}
+
+// TemplateTail
+
+type TemplateTail struct {
+ NodeBase
+ TemplateLiteralLikeBase
+}
+
+func (f *NodeFactory) NewTemplateTail(text string, rawText string, templateFlags TokenFlags) *Node {
+ data := &TemplateTail{}
+ data.text = text
+ data.rawText = rawText
+ data.templateFlags = templateFlags
+ return f.NewNode(SyntaxKindTemplateTail, data)
+}
+
+// TemplateLiteralTypeNode
+
+type TemplateLiteralTypeNode struct {
+ TypeNodeBase
+ head *Node
+ templateSpans []*Node
+}
+
+func (f *NodeFactory) NewTemplateLiteralTypeNode(head *Node, templateSpans []*Node) *Node {
+ data := &TemplateLiteralTypeNode{}
+ data.head = head
+ data.templateSpans = templateSpans
+ return f.NewNode(SyntaxKindTemplateLiteralType, data)
+}
+
+func (node *TemplateLiteralTypeNode) ForEachChild(v Visitor) bool {
+ return visit(v, node.head) || visitNodes(v, node.templateSpans)
+}
+
+// TemplateLiteralTypeSpan
+
+type TemplateLiteralTypeSpan struct {
+ NodeBase
+ typeNode *Node
+ literal *Node
+}
+
+func (f *NodeFactory) NewTemplateLiteralTypeSpan(typeNode *Node, literal *Node) *Node {
+ data := &TemplateLiteralTypeSpan{}
+ data.typeNode = typeNode
+ data.literal = literal
+ return f.NewNode(SyntaxKindTemplateLiteralTypeSpan, data)
+}
+
+func (node *TemplateLiteralTypeSpan) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeNode) || visit(v, node.literal)
+}
+
+/// A JSX expression of the form ...
+
+type JsxElement struct {
+ ExpressionBase
+ openingElement *Node
+ children []*Node
+ closingElement *Node
+}
+
+func (f *NodeFactory) NewJsxElement(openingElement *Node, children []*Node, closingElement *Node) *Node {
+ data := &JsxElement{}
+ data.openingElement = openingElement
+ data.children = children
+ data.closingElement = closingElement
+ return f.NewNode(SyntaxKindJsxElement, data)
+}
+
+func (node *JsxElement) ForEachChild(v Visitor) bool {
+ return visit(v, node.openingElement) || visitNodes(v, node.children) || visit(v, node.closingElement)
+}
+
+// JsxAttributes
+
+type JsxAttributes struct {
+ ExpressionBase
+ DeclarationBase
+ properties []*JsxAttributeLike
+}
+
+func (f *NodeFactory) NewJsxAttributes(properties []*JsxAttributeLike) *Node {
+ data := &JsxAttributes{}
+ data.properties = properties
+ return f.NewNode(SyntaxKindJsxAttributes, data)
+}
+
+func (node *JsxAttributes) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.properties)
+}
+
+// JsxNamespacedName
+
+type JsxNamespacedName struct {
+ ExpressionBase
+ name *Node
+ namespace *Node
+}
+
+func (f *NodeFactory) NewJsxNamespacedName(name *Node, namespace *Node) *Node {
+ data := &JsxNamespacedName{}
+ data.name = name
+ data.namespace = namespace
+ return f.NewNode(SyntaxKindJsxNamespacedName, data)
+}
+
+func (node *JsxNamespacedName) ForEachChild(v Visitor) bool {
+ return visit(v, node.name) || visit(v, node.namespace)
+}
+
+func isJsxNamespacedName(node *Node) bool {
+ return node.kind == SyntaxKindJsxNamespacedName
+}
+
+/// The opening element of a ... JsxElement
+
+type JsxOpeningElement struct {
+ ExpressionBase
+ tagName *Node // Identifier | KeywordExpression | PropertyAccessExpression | JsxNamespacedName
+ typeArguments *Node
+ attributes *Node
+}
+
+func (f *NodeFactory) NewJsxOpeningElement(tagName *Node, typeArguments *Node, attributes *Node) *Node {
+ data := &JsxOpeningElement{}
+ data.tagName = tagName
+ data.typeArguments = typeArguments
+ data.attributes = attributes
+ return f.NewNode(SyntaxKindJsxOpeningElement, data)
+}
+
+func (node *JsxOpeningElement) ForEachChild(v Visitor) bool {
+ return visit(v, node.tagName) || visit(v, node.typeArguments) || visit(v, node.attributes)
+}
+
+func isJsxOpeningElement(node *Node) bool {
+ return node.kind == SyntaxKindJsxOpeningElement
+}
+
+/// A JSX expression of the form
+
+type JsxSelfClosingElement struct {
+ ExpressionBase
+ tagName *Node // Identifier | KeywordExpression | PropertyAccessExpression | JsxNamespacedName
+ typeArguments *Node
+ attributes *Node
+}
+
+func (f *NodeFactory) NewJsxSelfClosingElement(tagName *Node, typeArguments *Node, attributes *Node) *Node {
+ data := &JsxSelfClosingElement{}
+ data.tagName = tagName
+ data.typeArguments = typeArguments
+ data.attributes = attributes
+ return f.NewNode(SyntaxKindJsxSelfClosingElement, data)
+}
+
+func (node *JsxSelfClosingElement) ForEachChild(v Visitor) bool {
+ return visit(v, node.tagName) || visit(v, node.typeArguments) || visit(v, node.attributes)
+}
+
+/// A JSX expression of the form <>...>
+
+type JsxFragment struct {
+ ExpressionBase
+ openingFragment *Node
+ children []*Node
+ closingFragment *Node
+}
+
+func (f *NodeFactory) NewJsxFragment(openingFragment *Node, children []*Node, closingFragment *Node) *Node {
+ data := &JsxFragment{}
+ data.openingFragment = openingFragment
+ data.children = children
+ data.closingFragment = closingFragment
+ return f.NewNode(SyntaxKindJsxFragment, data)
+}
+
+func (node *JsxFragment) ForEachChild(v Visitor) bool {
+ return visit(v, node.openingFragment) || visitNodes(v, node.children) || visit(v, node.closingFragment)
+}
+
+/// The opening element of a <>...> JsxFragment
+
+type JsxOpeningFragment struct {
+ ExpressionBase
+}
+
+func (f *NodeFactory) NewJsxOpeningFragment() *Node {
+ return f.NewNode(SyntaxKindJsxOpeningFragment, &JsxOpeningFragment{})
+}
+
+func isJsxOpeningFragment(node *Node) bool {
+ return node.kind == SyntaxKindJsxOpeningFragment
+}
+
+/// The closing element of a <>...> JsxFragment
+
+type JsxClosingFragment struct {
+ ExpressionBase
+}
+
+func (f *NodeFactory) NewJsxClosingFragment() *Node {
+ return f.NewNode(SyntaxKindJsxClosingFragment, &JsxClosingFragment{})
+}
+
+// JsxAttribute
+
+type JsxAttribute struct {
+ NodeBase
+ DeclarationBase
+ name *Node
+ /// JSX attribute initializers are optional; is sugar for
+ initializer *Node
+}
+
+func (f *NodeFactory) NewJsxAttribute(name *Node, initializer *Node) *Node {
+ data := &JsxAttribute{}
+ data.name = name
+ data.initializer = initializer
+ return f.NewNode(SyntaxKindJsxAttribute, data)
+}
+
+func (node *JsxAttribute) ForEachChild(v Visitor) bool {
+ return visit(v, node.name) || visit(v, node.initializer)
+}
+
+func isJsxAttribute(node *Node) bool {
+ return node.kind == SyntaxKindJsxAttribute
+}
+
+// JsxSpreadAttribute
+
+type JsxSpreadAttribute struct {
+ NodeBase
+ expression *Node
+}
+
+func (f *NodeFactory) NewJsxSpreadAttribute(expression *Node) *Node {
+ data := &JsxSpreadAttribute{}
+ data.expression = expression
+ return f.NewNode(SyntaxKindJsxAttribute, data)
+}
+
+func (node *JsxSpreadAttribute) ForEachChild(v Visitor) bool {
+ return visit(v, node.expression)
+}
+
+// JsxClosingElement
+
+type JsxClosingElement struct {
+ NodeBase
+ tagName *Node // Identifier | KeywordExpression | PropertyAccessExpression | JsxNamespacedName
+}
+
+func (f *NodeFactory) NewJsxClosingElement(tagName *Node) *Node {
+ data := &JsxClosingElement{}
+ data.tagName = tagName
+ return f.NewNode(SyntaxKindJsxClosingElement, data)
+}
+
+func (node *JsxClosingElement) ForEachChild(v Visitor) bool {
+ return visit(v, node.tagName)
+}
+
+// JsxExpression
+
+type JsxExpression struct {
+ ExpressionBase
+ dotDotDotToken *Node
+ expression *Node
+}
+
+func (f *NodeFactory) NewJsxExpression(dotDotDotToken *Node, expression *Node) *Node {
+ data := &JsxExpression{}
+ data.dotDotDotToken = dotDotDotToken
+ data.expression = expression
+ return f.NewNode(SyntaxKindJsxExpression, data)
+}
+
+func (node *JsxExpression) ForEachChild(v Visitor) bool {
+ return visit(v, node.dotDotDotToken) || visit(v, node.expression)
+}
+
+// JsxText
+
+type JsxText struct {
+ ExpressionBase
+ LiteralLikeBase
+ containsOnlyTriviaWhiteSpaces bool
+}
+
+func (f *NodeFactory) NewJsxText(text string, containsOnlyTriviaWhiteSpace bool) *Node {
+ data := &JsxText{}
+ data.text = text
+ data.containsOnlyTriviaWhiteSpaces = containsOnlyTriviaWhiteSpace
+ return f.NewNode(SyntaxKindJsxText, data)
+}
+
+// JSDocNonNullableType
+
+type JSDocNonNullableType struct {
+ TypeNodeBase
+ typeNode *Node
+ postfix bool
+}
+
+func (f *NodeFactory) NewJSDocNonNullableType(typeNode *Node, postfix bool) *Node {
+ data := &JSDocNonNullableType{}
+ data.typeNode = typeNode
+ data.postfix = postfix
+ return f.NewNode(SyntaxKindJSDocNonNullableType, data)
+}
+
+func (node *JSDocNonNullableType) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeNode)
+}
+
+// JSDocNullableType
+
+type JSDocNullableType struct {
+ TypeNodeBase
+ typeNode *Node
+ postfix bool
+}
+
+func (f *NodeFactory) NewJSDocNullableType(typeNode *Node, postfix bool) *Node {
+ data := &JSDocNullableType{}
+ data.typeNode = typeNode
+ data.postfix = postfix
+ return f.NewNode(SyntaxKindJSDocNullableType, data)
+}
+
+func (node *JSDocNullableType) ForEachChild(v Visitor) bool {
+ return visit(v, node.typeNode)
+}
+
+// PatternAmbientModule
+
+type PatternAmbientModule struct {
+ pattern Pattern
+ symbol *Symbol
+}
+
+// SourceFile
+
+type SourceFile struct {
+ NodeBase
+ DeclarationBase
+ LocalsContainerBase
+ text string
+ fileName string
+ path string
+ statements []*Statement
+ diagnostics []*Diagnostic
+ bindDiagnostics []*Diagnostic
+ bindSuggestionDiagnostics []*Diagnostic
+ lineMap []TextPos
+ languageVersion ScriptTarget
+ languageVariant LanguageVariant
+ scriptKind ScriptKind
+ externalModuleIndicator *Node
+ endFlowNode *FlowNode
+ jsGlobalAugmentations SymbolTable
+ isDeclarationFile bool
+ isBound bool
+ moduleReferencesProcessed bool
+ usesUriStyleNodeCoreModules Tristate
+ symbolCount int
+ classifiableNames map[string]bool
+ imports []*LiteralLikeNode
+ moduleAugmentations []*ModuleName
+ patternAmbientModules []PatternAmbientModule
+ ambientModuleNames []string
+}
+
+func (f *NodeFactory) NewSourceFile(text string, fileName string, statements []*Node) *Node {
+ data := &SourceFile{}
+ data.text = text
+ data.fileName = fileName
+ data.statements = statements
+ data.languageVersion = ScriptTargetLatest
+ return f.NewNode(SyntaxKindSourceFile, data)
+}
+
+func (node *SourceFile) FileName() string {
+ return node.fileName
+}
+
+func (node *SourceFile) Path() string {
+ return node.path
+}
+
+func (node *SourceFile) Diagnostics() []*Diagnostic {
+ return node.diagnostics
+}
+
+func (node *SourceFile) BindDiagnostics() []*Diagnostic {
+ return node.bindDiagnostics
+}
+
+func (node *SourceFile) ForEachChild(v Visitor) bool {
+ return visitNodes(v, node.statements)
+}
+
+func isSourceFile(node *Node) bool {
+ return node.kind == SyntaxKindSourceFile
+}
diff --git a/internal/compiler/binder.go b/internal/compiler/binder.go
new file mode 100644
index 0000000000..5f2f909430
--- /dev/null
+++ b/internal/compiler/binder.go
@@ -0,0 +1,2783 @@
+package compiler
+
+import (
+ "slices"
+ "strconv"
+
+ "github.com/microsoft/typescript-go/internal/compiler/diagnostics"
+)
+
+type ContainerFlags int32
+
+const (
+ // The current node is not a container, and no container manipulation should happen before
+ // recursing into it.
+ ContainerFlagsNone ContainerFlags = 0
+ // The current node is a container. It should be set as the current container (and block-
+ // container) before recursing into it. The current node does not have locals. Examples:
+ //
+ // Classes, ObjectLiterals, TypeLiterals, Interfaces...
+ ContainerFlagsIsContainer ContainerFlags = 1 << 0
+ // The current node is a block-scoped-container. It should be set as the current block-
+ // container before recursing into it. Examples:
+ //
+ // Blocks (when not parented by functions), Catch clauses, For/For-in/For-of statements...
+ ContainerFlagsIsBlockScopedContainer ContainerFlags = 1 << 1
+ // The current node is the container of a control flow path. The current control flow should
+ // be saved and restored, and a new control flow initialized within the container.
+ ContainerFlagsIsControlFlowContainer ContainerFlags = 1 << 2
+ ContainerFlagsIsFunctionLike ContainerFlags = 1 << 3
+ ContainerFlagsIsFunctionExpression ContainerFlags = 1 << 4
+ ContainerFlagsHasLocals ContainerFlags = 1 << 5
+ ContainerFlagsIsInterface ContainerFlags = 1 << 6
+ ContainerFlagsIsObjectLiteralOrClassExpressionMethodOrAccessor ContainerFlags = 1 << 7
+)
+
+type Binder struct {
+ file *SourceFile
+ options *CompilerOptions
+ languageVersion ScriptTarget
+ parent *Node
+ container *Node
+ thisParentContainer *Node
+ blockScopeContainer *Node
+ lastContainer *Node
+ currentFlow *FlowNode
+ currentBreakTarget *FlowLabel
+ currentContinueTarget *FlowLabel
+ currentReturnTarget *FlowLabel
+ currentTrueTarget *FlowLabel
+ currentFalseTarget *FlowLabel
+ currentExceptionTarget *FlowLabel
+ preSwitchCaseFlow *FlowNode
+ activeLabelList *ActiveLabel
+ emitFlags NodeFlags
+ seenThisKeyword bool
+ hasExplicitReturn bool
+ hasFlowEffects bool
+ inStrictMode bool
+ inAssignmentPattern bool
+ symbolCount int
+ classifiableNames map[string]bool
+ symbolPool Pool[Symbol]
+ flowNodePool Pool[FlowNode]
+ flowListPool Pool[FlowList]
+ singleDeclarations []*Node
+}
+
+type ModuleInstanceState int32
+
+const (
+ ModuleInstanceStateUnknown ModuleInstanceState = iota
+ ModuleInstanceStateNonInstantiated
+ ModuleInstanceStateInstantiated
+ ModuleInstanceStateConstEnumOnly
+)
+
+type ActiveLabel struct {
+ next *ActiveLabel
+ breakTarget *FlowLabel
+ continueTarget *FlowLabel
+ name string
+ referenced bool
+}
+
+func (label *ActiveLabel) BreakTarget() *FlowNode { return label.breakTarget }
+func (label *ActiveLabel) ContinueTarget() *FlowNode { return label.continueTarget }
+
+func bindSourceFile(file *SourceFile, options *CompilerOptions) {
+ if !file.isBound {
+ b := &Binder{}
+ b.file = file
+ b.options = options
+ b.languageVersion = getEmitScriptTarget(options)
+ b.classifiableNames = make(map[string]bool)
+ b.bind(file.AsNode())
+ file.isBound = true
+ file.symbolCount = b.symbolCount
+ file.classifiableNames = b.classifiableNames
+ }
+}
+
+func (b *Binder) newSymbol(flags SymbolFlags, name string) *Symbol {
+ b.symbolCount++
+ result := b.symbolPool.New()
+ result.flags = flags
+ result.name = name
+ return result
+}
+
+func getMembers(symbol *Symbol) SymbolTable {
+ if symbol.members == nil {
+ symbol.members = make(SymbolTable)
+ }
+ return symbol.members
+}
+
+func getExports(symbol *Symbol) SymbolTable {
+ if symbol.exports == nil {
+ symbol.exports = make(SymbolTable)
+ }
+ return symbol.exports
+}
+
+func getLocals(container *Node) SymbolTable {
+ data := container.LocalsContainerData()
+ if data.locals == nil {
+ data.locals = make(SymbolTable)
+ }
+ return data.locals
+}
+
+/**
+ * Declares a Symbol for the node and adds it to symbols. Reports errors for conflicting identifier names.
+ * @param symbolTable - The symbol table which node will be added to.
+ * @param parent - node's parent declaration.
+ * @param node - The declaration to be added to the symbol table
+ * @param includes - The SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.)
+ * @param excludes - The flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations.
+ */
+func (b *Binder) declareSymbol(symbolTable SymbolTable, parent *Symbol, node *Node, includes SymbolFlags, excludes SymbolFlags) *Symbol {
+ return b.declareSymbolEx(symbolTable, parent, node, includes, excludes, false /*isReplaceableByMethod*/, false /*isComputedName*/)
+}
+
+func (b *Binder) declareSymbolEx(symbolTable SymbolTable, parent *Symbol, node *Node, includes SymbolFlags, excludes SymbolFlags, isReplaceableByMethod bool, isComputedName bool) *Symbol {
+ //Debug.assert(isComputedName || !hasDynamicName(node))
+ isDefaultExport := hasSyntacticModifier(node, ModifierFlagsDefault) || isExportSpecifier(node) && moduleExportNameIsDefault(node.AsExportSpecifier().name)
+ // The exported symbol for an export default function/class node is always named "default"
+ var name string
+ switch {
+ case isComputedName:
+ name = InternalSymbolNameComputed
+ case isDefaultExport && b.parent != nil:
+ name = InternalSymbolNameDefault
+ default:
+ name = b.getDeclarationName(node)
+ }
+ var symbol *Symbol
+ if name == InternalSymbolNameMissing {
+ symbol = b.newSymbol(SymbolFlagsNone, InternalSymbolNameMissing)
+ } else {
+ // Check and see if the symbol table already has a symbol with this name. If not,
+ // create a new symbol with this name and add it to the table. Note that we don't
+ // give the new symbol any flags *yet*. This ensures that it will not conflict
+ // with the 'excludes' flags we pass in.
+ //
+ // If we do get an existing symbol, see if it conflicts with the new symbol we're
+ // creating. For example, a 'var' symbol and a 'class' symbol will conflict within
+ // the same symbol table. If we have a conflict, report the issue on each
+ // declaration we have for this symbol, and then create a new symbol for this
+ // declaration.
+ //
+ // Note that when properties declared in Javascript constructors
+ // (marked by isReplaceableByMethod) conflict with another symbol, the property loses.
+ // Always. This allows the common Javascript pattern of overwriting a prototype method
+ // with an bound instance method of the same type: `this.method = this.method.bind(this)`
+ //
+ // If we created a new symbol, either because we didn't have a symbol with this name
+ // in the symbol table, or we conflicted with an existing symbol, then just add this
+ // node as the sole declaration of the new symbol.
+ //
+ // Otherwise, we'll be merging into a compatible existing symbol (for example when
+ // you have multiple 'vars' with the same name in the same container). In this case
+ // just add this node into the declarations list of the symbol.
+ symbol = symbolTable[name]
+ if includes&SymbolFlagsClassifiable != 0 {
+ b.classifiableNames[name] = true
+ }
+ if symbol == nil {
+ symbol = b.newSymbol(SymbolFlagsNone, name)
+ symbolTable[name] = symbol
+ if isReplaceableByMethod {
+ symbol.isReplaceableByMethod = true
+ }
+ } else if isReplaceableByMethod && !symbol.isReplaceableByMethod {
+ // A symbol already exists, so don't add this as a declaration.
+ return symbol
+ } else if symbol.flags&excludes != 0 {
+ if symbol.isReplaceableByMethod {
+ // Javascript constructor-declared symbols can be discarded in favor of
+ // prototype symbols like methods.
+ symbol = b.newSymbol(SymbolFlagsNone, name)
+ symbolTable[name] = symbol
+ } else if includes&SymbolFlagsVariable == 0 || symbol.flags&SymbolFlagsAssignment == 0 {
+ // Assignment declarations are allowed to merge with variables, no matter what other flags they have.
+ if node.Name() != nil {
+ setParent(node.Name(), node)
+ }
+ // Report errors every position with duplicate declaration
+ // Report errors on previous encountered declarations
+ var message *diagnostics.Message
+ if symbol.flags&SymbolFlagsBlockScopedVariable != 0 {
+ message = diagnostics.Cannot_redeclare_block_scoped_variable_0
+ } else {
+ message = diagnostics.Duplicate_identifier_0
+ }
+ messageNeedsName := true
+ if symbol.flags&SymbolFlagsEnum != 0 || includes&SymbolFlagsEnum != 0 {
+ message = diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations
+ messageNeedsName = false
+ }
+ multipleDefaultExports := false
+ if len(symbol.declarations) != 0 {
+ // If the current node is a default export of some sort, then check if
+ // there are any other default exports that we need to error on.
+ // We'll know whether we have other default exports depending on if `symbol` already has a declaration list set.
+ if isDefaultExport {
+ message = diagnostics.A_module_cannot_have_multiple_default_exports
+ messageNeedsName = false
+ multipleDefaultExports = true
+ } else {
+ // This is to properly report an error in the case "export default { }" is after export default of class declaration or function declaration.
+ // Error on multiple export default in the following case:
+ // 1. multiple export default of class declaration or function declaration by checking NodeFlags.Default
+ // 2. multiple export default of export assignment. This one doesn't have NodeFlags.Default on (as export default doesn't considered as modifiers)
+ if len(symbol.declarations) != 0 && isExportAssignment(node) && !node.AsExportAssignment().isExportEquals {
+ message = diagnostics.A_module_cannot_have_multiple_default_exports
+ messageNeedsName = false
+ multipleDefaultExports = true
+ }
+ }
+ }
+ var relatedInformation []*Diagnostic
+ if isTypeAliasDeclaration(node) && nodeIsMissing(node.AsTypeAliasDeclaration().typeNode) && hasSyntacticModifier(node, ModifierFlagsExport) && symbol.flags&(SymbolFlagsAlias|SymbolFlagsType|SymbolFlagsNamespace) != 0 {
+ // export type T; - may have meant export type { T }?
+ relatedInformation = append(relatedInformation, b.createDiagnosticForNode(node, diagnostics.Did_you_mean_0,
+ "export type { "+node.AsTypeAliasDeclaration().name.AsIdentifier().text+" }"))
+ }
+ var declarationName *Node = getNameOfDeclaration(node)
+ if declarationName == nil {
+ declarationName = node
+ }
+ for index, declaration := range symbol.declarations {
+ var decl *Node = getNameOfDeclaration(declaration)
+ if decl == nil {
+ decl = declaration
+ }
+ var diag *Diagnostic
+ if messageNeedsName {
+ diag = b.createDiagnosticForNode(decl, message, b.getDisplayName(declaration))
+ } else {
+ diag = b.createDiagnosticForNode(decl, message)
+ }
+ if multipleDefaultExports {
+ addRelatedInfo(diag, b.createDiagnosticForNode(declarationName, ifElse(index == 0, diagnostics.Another_export_default_is_here, diagnostics.X_and_here)))
+ }
+ b.addDiagnostic(diag)
+ if multipleDefaultExports {
+ relatedInformation = append(relatedInformation, b.createDiagnosticForNode(decl, diagnostics.The_first_export_default_is_here))
+ }
+ }
+ var diag *Diagnostic
+ if messageNeedsName {
+ diag = b.createDiagnosticForNode(declarationName, message, b.getDisplayName(node))
+ } else {
+ diag = b.createDiagnosticForNode(declarationName, message)
+ }
+ b.addDiagnostic(addRelatedInfo(diag, relatedInformation...))
+ symbol = b.newSymbol(SymbolFlagsNone, name)
+ }
+ }
+ }
+ b.addDeclarationToSymbol(symbol, node, includes)
+ if symbol.parent == nil {
+ symbol.parent = parent
+ } else if symbol.parent != parent {
+ panic("Existing symbol parent should match new one")
+ }
+ return symbol
+}
+
+// Should not be called on a declaration with a computed property name,
+// unless it is a well known Symbol.
+func (b *Binder) getDeclarationName(node *Node) string {
+ if isExportAssignment(node) {
+ return ifElse(node.AsExportAssignment().isExportEquals, InternalSymbolNameExportEquals, InternalSymbolNameDefault)
+ }
+ name := getNameOfDeclaration(node)
+ if name != nil {
+ if isAmbientModule(node) {
+ moduleName := getTextOfIdentifierOrLiteral(name)
+ if isGlobalScopeAugmentation(node) {
+ return InternalSymbolNameGlobal
+ }
+ return "\"" + moduleName + "\""
+ }
+ if isPrivateIdentifier(name) {
+ // containingClass exists because private names only allowed inside classes
+ containingClass := getContainingClass(node)
+ if containingClass == nil {
+ // we can get here in cases where there is already a parse error.
+ return InternalSymbolNameMissing
+ }
+ containingClassSymbol := getSymbolFromNode(containingClass)
+ return getSymbolNameForPrivateIdentifier(containingClassSymbol, getTextOfIdentifierOrLiteral(name))
+ }
+ if isPropertyNameLiteral(name) {
+ return getTextOfIdentifierOrLiteral(name)
+ }
+ if isComputedPropertyName(name) {
+ nameExpression := name.AsComputedPropertyName().expression
+ // treat computed property names where expression is string/numeric literal as just string/numeric literal
+ if isStringOrNumericLiteralLike(nameExpression) {
+ return getTextOfIdentifierOrLiteral(nameExpression)
+ }
+ if isSignedNumericLiteral(nameExpression) {
+ unaryExpression := nameExpression.AsPrefixUnaryExpression()
+ return TokenToString(unaryExpression.operator) + getTextOfIdentifierOrLiteral(unaryExpression.operand)
+ }
+ panic("Only computed properties with literal names have declaration names")
+ }
+ // if isJsxNamespacedName(name) {
+ // return getEscapedTextOfJsxNamespacedName(name)
+ // }
+ return InternalSymbolNameMissing
+ }
+ switch node.kind {
+ case SyntaxKindConstructor:
+ return InternalSymbolNameConstructor
+ case SyntaxKindFunctionType, SyntaxKindCallSignature:
+ return InternalSymbolNameCall
+ case SyntaxKindConstructorType, SyntaxKindConstructSignature:
+ return InternalSymbolNameNew
+ case SyntaxKindIndexSignature:
+ return InternalSymbolNameIndex
+ case SyntaxKindExportDeclaration:
+ return InternalSymbolNameExportStar
+ case SyntaxKindSourceFile:
+ return InternalSymbolNameExportEquals
+ }
+ return InternalSymbolNameMissing
+}
+
+func (b *Binder) getDisplayName(node *Node) string {
+ nameNode := node.Name()
+ if nameNode != nil {
+ return declarationNameToString(nameNode)
+ }
+ name := b.getDeclarationName(node)
+ if name != InternalSymbolNameMissing {
+ return name
+ }
+ return "(Missing)"
+}
+
+func moduleExportNameIsDefault(node *Node) bool {
+ return getTextOfIdentifierOrLiteral(node) == InternalSymbolNameDefault
+}
+
+func getSymbolNameForPrivateIdentifier(containingClassSymbol *Symbol, description string) string {
+ return InternalSymbolNamePrefix + "#" + strconv.Itoa(int(getSymbolId(containingClassSymbol))) + "@" + description
+}
+
+func (b *Binder) declareModuleMember(node *Node, symbolFlags SymbolFlags, symbolExcludes SymbolFlags) *Symbol {
+ hasExportModifier := getCombinedModifierFlags(node)&ModifierFlagsExport != 0
+ if symbolFlags&SymbolFlagsAlias != 0 {
+ if node.kind == SyntaxKindExportSpecifier || (node.kind == SyntaxKindImportEqualsDeclaration && hasExportModifier) {
+ return b.declareSymbol(getExports(b.container.Symbol()), b.container.Symbol(), node, symbolFlags, symbolExcludes)
+ }
+ return b.declareSymbol(getLocals(b.container), nil /*parent*/, node, symbolFlags, symbolExcludes)
+ }
+ // Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue flag,
+ // and an associated export symbol with all the correct flags set on it. There are 2 main reasons:
+ //
+ // 1. We treat locals and exports of the same name as mutually exclusive within a container.
+ // That means the binder will issue a Duplicate Identifier error if you mix locals and exports
+ // with the same name in the same container.
+ // TODO: Make this a more specific error and decouple it from the exclusion logic.
+ // 2. When we checkIdentifier in the checker, we set its resolved symbol to the local symbol,
+ // but return the export symbol (by calling getExportSymbolOfValueSymbolIfExported). That way
+ // when the emitter comes back to it, it knows not to qualify the name if it was found in a containing scope.
+ //
+ // NOTE: Nested ambient modules always should go to to 'locals' table to prevent their automatic merge
+ // during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation
+ // and this case is specially handled. Module augmentations should only be merged with original module definition
+ // and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed.
+ if !isAmbientModule(node) && (hasExportModifier || b.container.flags&NodeFlagsExportContext != 0) {
+ if !isLocalsContainer(b.container) || (hasSyntacticModifier(node, ModifierFlagsDefault) && b.getDeclarationName(node) == InternalSymbolNameMissing) {
+ return b.declareSymbol(getExports(b.container.Symbol()), b.container.Symbol(), node, symbolFlags, symbolExcludes)
+ // No local symbol for an unnamed default!
+ }
+ exportKind := SymbolFlagsNone
+ if symbolFlags&SymbolFlagsValue != 0 {
+ exportKind = SymbolFlagsExportValue
+ }
+ local := b.declareSymbol(getLocals(b.container), nil /*parent*/, node, exportKind, symbolExcludes)
+ local.exportSymbol = b.declareSymbol(getExports(b.container.Symbol()), b.container.Symbol(), node, symbolFlags, symbolExcludes)
+ node.ExportableData().localSymbol = local
+ return local
+ }
+ return b.declareSymbol(getLocals(b.container), nil /*parent*/, node, symbolFlags, symbolExcludes)
+}
+
+func (b *Binder) declareClassMember(node *Node, symbolFlags SymbolFlags, symbolExcludes SymbolFlags) *Symbol {
+ if isStatic(node) {
+ return b.declareSymbol(getExports(b.container.Symbol()), b.container.Symbol(), node, symbolFlags, symbolExcludes)
+ }
+ return b.declareSymbol(getMembers(b.container.Symbol()), b.container.Symbol(), node, symbolFlags, symbolExcludes)
+}
+
+func (b *Binder) declareSourceFileMember(node *Node, symbolFlags SymbolFlags, symbolExcludes SymbolFlags) *Symbol {
+ if isExternalModule(b.file) {
+ return b.declareModuleMember(node, symbolFlags, symbolExcludes)
+ }
+ return b.declareSymbol(getLocals(b.file.AsNode()), nil /*parent*/, node, symbolFlags, symbolExcludes)
+}
+
+func (b *Binder) declareSymbolAndAddToSymbolTable(node *Node, symbolFlags SymbolFlags, symbolExcludes SymbolFlags) *Symbol {
+ switch b.container.kind {
+ case SyntaxKindModuleDeclaration:
+ return b.declareModuleMember(node, symbolFlags, symbolExcludes)
+ case SyntaxKindSourceFile:
+ return b.declareSourceFileMember(node, symbolFlags, symbolExcludes)
+ case SyntaxKindClassExpression, SyntaxKindClassDeclaration:
+ return b.declareClassMember(node, symbolFlags, symbolExcludes)
+ case SyntaxKindEnumDeclaration:
+ return b.declareSymbol(getExports(b.container.Symbol()), b.container.Symbol(), node, symbolFlags, symbolExcludes)
+ case SyntaxKindTypeLiteral, SyntaxKindJSDocTypeLiteral, SyntaxKindObjectLiteralExpression, SyntaxKindInterfaceDeclaration, SyntaxKindJsxAttributes:
+ return b.declareSymbol(getMembers(b.container.Symbol()), b.container.Symbol(), node, symbolFlags, symbolExcludes)
+ case SyntaxKindFunctionType, SyntaxKindConstructorType, SyntaxKindCallSignature, SyntaxKindConstructSignature, SyntaxKindJSDocSignature,
+ SyntaxKindIndexSignature, SyntaxKindMethodDeclaration, SyntaxKindMethodSignature, SyntaxKindConstructor, SyntaxKindGetAccessor,
+ SyntaxKindSetAccessor, SyntaxKindFunctionDeclaration, SyntaxKindFunctionExpression, SyntaxKindArrowFunction, SyntaxKindJSDocFunctionType,
+ SyntaxKindClassStaticBlockDeclaration, SyntaxKindTypeAliasDeclaration, SyntaxKindMappedType:
+ return b.declareSymbol(getLocals(b.container), nil /*parent*/, node, symbolFlags, symbolExcludes)
+ }
+ panic("Unhandled case in declareSymbolAndAddToSymbolTable")
+}
+
+func (b *Binder) newFlowNode(flags FlowFlags) *FlowNode {
+ result := b.flowNodePool.New()
+ result.flags = flags
+ return result
+}
+
+func (b *Binder) newFlowNodeEx(flags FlowFlags, node any, antecedent *FlowNode) *FlowNode {
+ result := b.newFlowNode(flags)
+ result.node = node
+ result.antecedent = antecedent
+ return result
+}
+
+func (b *Binder) createLoopLabel() *FlowLabel {
+ return b.newFlowNode(FlowFlagsLoopLabel)
+}
+
+func (b *Binder) createBranchLabel() *FlowLabel {
+ return b.newFlowNode(FlowFlagsBranchLabel)
+}
+
+func (b *Binder) createReduceLabel(target *FlowLabel, antecedents *FlowList, antecedent *FlowNode) *FlowNode {
+ return b.newFlowNodeEx(FlowFlagsReduceLabel, &FlowReduceLabelData{target, antecedents}, antecedent)
+}
+
+func (b *Binder) createFlowCondition(flags FlowFlags, antecedent *FlowNode, expression *Node) *FlowNode {
+ if antecedent.flags&FlowFlagsUnreachable != 0 {
+ return antecedent
+ }
+ if expression == nil {
+ if flags&FlowFlagsTrueCondition != 0 {
+ return antecedent
+ }
+ return unreachableFlow
+ }
+ if (expression.kind == SyntaxKindTrueKeyword && flags&FlowFlagsFalseCondition != 0 || expression.kind == SyntaxKindFalseKeyword && flags&FlowFlagsTrueCondition != 0) && !isExpressionOfOptionalChainRoot(expression) && !isNullishCoalesce(expression.parent) {
+ return unreachableFlow
+ }
+ if !isNarrowingExpression(expression) {
+ return antecedent
+ }
+ setFlowNodeReferenced(antecedent)
+ return b.newFlowNodeEx(flags, expression, antecedent)
+}
+
+func (b *Binder) createFlowMutation(flags FlowFlags, antecedent *FlowNode, node *Node) *FlowNode {
+ setFlowNodeReferenced(antecedent)
+ b.hasFlowEffects = true
+ result := b.newFlowNodeEx(flags, node, antecedent)
+ if b.currentExceptionTarget != nil {
+ b.addAntecedent(b.currentExceptionTarget, result)
+ }
+ return result
+}
+
+func (b *Binder) createFlowSwitchClause(antecedent *FlowNode, switchStatement *SwitchStatement, clauseStart int32, clauseEnd int32) *FlowNode {
+ setFlowNodeReferenced(antecedent)
+ return b.newFlowNodeEx(FlowFlagsSwitchClause, &FlowSwitchClauseData{switchStatement, clauseStart, clauseEnd}, antecedent)
+}
+
+func (b *Binder) createFlowCall(antecedent *FlowNode, node *CallExpression) *FlowNode {
+ setFlowNodeReferenced(antecedent)
+ b.hasFlowEffects = true
+ return b.newFlowNodeEx(FlowFlagsCall, node, antecedent)
+}
+
+func (b *Binder) newFlowList(head *FlowNode, tail *FlowList) *FlowList {
+ result := b.flowListPool.New()
+ result.node = head
+ result.next = tail
+ return result
+}
+
+func (b *Binder) combineFlowLists(head *FlowList, tail *FlowList) *FlowList {
+ if head == nil {
+ return tail
+ }
+ return b.newFlowList(head.node, b.combineFlowLists(head.next, tail))
+}
+
+func (b *Binder) newSingleDeclaration(declaration *Node) []*Node {
+ if len(b.singleDeclarations) == cap(b.singleDeclarations) {
+ b.singleDeclarations = make([]*Node, 0, nextPoolSize(len(b.singleDeclarations)))
+ }
+ index := len(b.singleDeclarations)
+ b.singleDeclarations = b.singleDeclarations[:index+1]
+ b.singleDeclarations[index] = declaration
+ return b.singleDeclarations[index : index+1 : index+1]
+}
+
+func setFlowNodeReferenced(flow *FlowNode) {
+ // On first reference we set the Referenced flag, thereafter we set the Shared flag
+ if flow.flags&FlowFlagsReferenced == 0 {
+ flow.flags |= FlowFlagsReferenced
+ } else {
+ flow.flags |= FlowFlagsShared
+ }
+}
+
+func hasAntecedent(list *FlowList, antecedent *FlowNode) bool {
+ for list != nil {
+ if list.node == antecedent {
+ return true
+ }
+ list = list.next
+ }
+ return false
+}
+
+func (b *Binder) addAntecedent(label *FlowLabel, antecedent *FlowNode) {
+ if antecedent.flags&FlowFlagsUnreachable == 0 && !hasAntecedent(label.antecedents, antecedent) {
+ label.antecedents = b.newFlowList(antecedent, label.antecedents)
+ setFlowNodeReferenced(antecedent)
+ }
+}
+
+func finishFlowLabel(label *FlowLabel) *FlowNode {
+ if label.antecedents == nil {
+ return unreachableFlow
+ }
+ if label.antecedents.next == nil {
+ return label.antecedents.node
+ }
+ return label
+}
+
+func (b *Binder) bind(node *Node) bool {
+ if !exists(node) {
+ return false
+ }
+ node.parent = b.parent
+ saveInStrictMode := b.inStrictMode
+ // Even though in the AST the jsdoc @typedef node belongs to the current node,
+ // its symbol might be in the same scope with the current node's symbol. Consider:
+ //
+ // /** @typedef {string | number} MyType */
+ // function foo();
+ //
+ // Here the current node is "foo", which is a container, but the scope of "MyType" should
+ // not be inside "foo". Therefore we always bind @typedef before bind the parent node,
+ // and skip binding this tag later when binding all the other jsdoc tags.
+
+ // First we bind declaration nodes to a symbol if possible. We'll both create a symbol
+ // and then potentially add the symbol to an appropriate symbol table. Possible
+ // destination symbol tables are:
+ //
+ // 1) The 'exports' table of the current container's symbol.
+ // 2) The 'members' table of the current container's symbol.
+ // 3) The 'locals' table of the current container.
+ //
+ // However, not all symbols will end up in any of these tables. 'Anonymous' symbols
+ // (like TypeLiterals for example) will not be put in any table.
+ b.bindWorker(node)
+ // Then we recurse into the children of the node to bind them as well. For certain
+ // symbols we do specialized work when we recurse. For example, we'll keep track of
+ // the current 'container' node when it changes. This helps us know which symbol table
+ // a local should go into for example. Since terminal nodes are known not to have
+ // children, as an optimization we don't process those.
+ if node.kind > SyntaxKindLastToken {
+ saveParent := b.parent
+ b.parent = node
+ containerFlags := getContainerFlags(node)
+ if containerFlags == ContainerFlagsNone {
+ b.bindChildren(node)
+ } else {
+ b.bindContainer(node, containerFlags)
+ }
+ b.parent = saveParent
+ } else {
+ saveParent := b.parent
+ if node.kind == SyntaxKindEndOfFile {
+ b.parent = node
+ }
+ b.parent = saveParent
+ }
+ b.inStrictMode = saveInStrictMode
+ return false
+}
+
+func (b *Binder) bindWorker(node *Node) {
+ switch node.kind {
+ case SyntaxKindIdentifier:
+ node.AsIdentifier().flowNode = b.currentFlow
+ b.checkContextualIdentifier(node)
+ case SyntaxKindThisKeyword, SyntaxKindSuperKeyword:
+ node.AsKeywordExpression().flowNode = b.currentFlow
+ case SyntaxKindQualifiedName:
+ if b.currentFlow != nil && isPartOfTypeQuery(node) {
+ node.AsQualifiedName().flowNode = b.currentFlow
+ }
+ case SyntaxKindMetaProperty:
+ node.AsMetaProperty().flowNode = b.currentFlow
+ case SyntaxKindPrivateIdentifier:
+ b.checkPrivateIdentifier(node)
+ case SyntaxKindPropertyAccessExpression, SyntaxKindElementAccessExpression:
+ if b.currentFlow != nil && isNarrowableReference(node) {
+ setFlowNode(node, b.currentFlow)
+ }
+ case SyntaxKindBinaryExpression:
+ if isFunctionPropertyAssignment(node) {
+ b.bindFunctionPropertyAssignment(node)
+ }
+ b.checkStrictModeBinaryExpression(node)
+ case SyntaxKindCatchClause:
+ b.checkStrictModeCatchClause(node)
+ case SyntaxKindDeleteExpression:
+ b.checkStrictModeDeleteExpression(node)
+ case SyntaxKindPostfixUnaryExpression:
+ b.checkStrictModePostfixUnaryExpression(node)
+ case SyntaxKindPrefixUnaryExpression:
+ b.checkStrictModePrefixUnaryExpression(node)
+ case SyntaxKindWithStatement:
+ b.checkStrictModeWithStatement(node)
+ case SyntaxKindLabeledStatement:
+ b.checkStrictModeLabeledStatement(node)
+ case SyntaxKindThisType:
+ b.seenThisKeyword = true
+ case SyntaxKindTypeParameter:
+ b.bindTypeParameter(node)
+ case SyntaxKindParameter:
+ b.bindParameter(node)
+ case SyntaxKindVariableDeclaration:
+ b.bindVariableDeclarationOrBindingElement(node)
+ case SyntaxKindBindingElement:
+ node.AsBindingElement().flowNode = b.currentFlow
+ b.bindVariableDeclarationOrBindingElement(node)
+ case SyntaxKindPropertyDeclaration, SyntaxKindPropertySignature:
+ b.bindPropertyWorker(node)
+ case SyntaxKindPropertyAssignment, SyntaxKindShorthandPropertyAssignment:
+ b.bindPropertyOrMethodOrAccessor(node, SymbolFlagsProperty, SymbolFlagsPropertyExcludes)
+ case SyntaxKindEnumMember:
+ b.bindPropertyOrMethodOrAccessor(node, SymbolFlagsEnumMember, SymbolFlagsEnumMemberExcludes)
+ case SyntaxKindCallSignature, SyntaxKindConstructSignature, SyntaxKindIndexSignature:
+ b.declareSymbolAndAddToSymbolTable(node, SymbolFlagsSignature, SymbolFlagsNone)
+ case SyntaxKindMethodDeclaration, SyntaxKindMethodSignature:
+ b.bindPropertyOrMethodOrAccessor(node, SymbolFlagsMethod|ifElse(getPostfixTokenFromNode(node) != nil, SymbolFlagsOptional, SymbolFlagsNone), ifElse(isObjectLiteralMethod(node), SymbolFlagsPropertyExcludes, SymbolFlagsMethodExcludes))
+ case SyntaxKindFunctionDeclaration:
+ b.bindFunctionDeclaration(node)
+ case SyntaxKindConstructor:
+ b.declareSymbolAndAddToSymbolTable(node, SymbolFlagsConstructor, SymbolFlagsNone)
+ case SyntaxKindGetAccessor:
+ b.bindPropertyOrMethodOrAccessor(node, SymbolFlagsGetAccessor, SymbolFlagsGetAccessorExcludes)
+ case SyntaxKindSetAccessor:
+ b.bindPropertyOrMethodOrAccessor(node, SymbolFlagsSetAccessor, SymbolFlagsSetAccessorExcludes)
+ case SyntaxKindFunctionType, SyntaxKindConstructorType:
+ // !!! SyntaxKindJSDocFunctionType
+ // !!! SyntaxKindJSDocSignature
+ b.bindFunctionOrConstructorType(node)
+ case SyntaxKindTypeLiteral, SyntaxKindMappedType:
+ // !!! SyntaxKindJSDocTypeLiteral
+ b.bindAnonymousDeclaration(node, SymbolFlagsTypeLiteral, InternalSymbolNameType)
+ case SyntaxKindObjectLiteralExpression:
+ b.bindAnonymousDeclaration(node, SymbolFlagsObjectLiteral, InternalSymbolNameObject)
+ case SyntaxKindFunctionExpression, SyntaxKindArrowFunction:
+ b.bindFunctionExpression(node)
+ case SyntaxKindClassExpression, SyntaxKindClassDeclaration:
+ b.inStrictMode = true
+ b.bindClassLikeDeclaration(node)
+ case SyntaxKindInterfaceDeclaration:
+ b.bindBlockScopedDeclaration(node, SymbolFlagsInterface, SymbolFlagsInterfaceExcludes)
+ case SyntaxKindTypeAliasDeclaration:
+ b.bindBlockScopedDeclaration(node, SymbolFlagsTypeAlias, SymbolFlagsTypeAliasExcludes)
+ case SyntaxKindEnumDeclaration:
+ b.bindEnumDeclaration(node)
+ case SyntaxKindModuleDeclaration:
+ b.bindModuleDeclaration(node)
+ case SyntaxKindImportEqualsDeclaration, SyntaxKindNamespaceImport, SyntaxKindImportSpecifier, SyntaxKindExportSpecifier:
+ b.declareSymbolAndAddToSymbolTable(node, SymbolFlagsAlias, SymbolFlagsAliasExcludes)
+ case SyntaxKindNamespaceExportDeclaration:
+ b.bindNamespaceExportDeclaration(node)
+ case SyntaxKindImportClause:
+ b.bindImportClause(node)
+ case SyntaxKindExportDeclaration:
+ b.bindExportDeclaration(node)
+ case SyntaxKindExportAssignment:
+ b.bindExportAssignment(node)
+ case SyntaxKindSourceFile:
+ b.updateStrictModeStatementList(node.AsSourceFile().statements)
+ b.bindSourceFileIfExternalModule()
+ case SyntaxKindBlock:
+ if isFunctionLikeOrClassStaticBlockDeclaration(node.parent) {
+ b.updateStrictModeStatementList(node.AsBlock().statements)
+ }
+ case SyntaxKindModuleBlock:
+ b.updateStrictModeStatementList(node.AsModuleBlock().statements)
+ case SyntaxKindJsxAttributes:
+ b.bindJsxAttributes(node)
+ case SyntaxKindJsxAttribute:
+ b.bindJsxAttribute(node, SymbolFlagsProperty, SymbolFlagsPropertyExcludes)
+ }
+}
+
+func (b *Binder) bindPropertyWorker(node *Node) {
+ isAutoAccessor := isAutoAccessorPropertyDeclaration(node)
+ includes := ifElse(isAutoAccessor, SymbolFlagsAccessor, SymbolFlagsProperty)
+ excludes := ifElse(isAutoAccessor, SymbolFlagsAccessorExcludes, SymbolFlagsPropertyExcludes)
+ b.bindPropertyOrMethodOrAccessor(node, includes|ifElse(getPostfixTokenFromNode(node) != nil, SymbolFlagsOptional, SymbolFlagsNone), excludes)
+}
+
+func (b *Binder) bindSourceFileIfExternalModule() {
+ b.setExportContextFlag(b.file.AsNode())
+ if isExternalModule(b.file) {
+ b.bindSourceFileAsExternalModule()
+ }
+ // !!!
+ // else if isJsonSourceFile(b.file) {
+ // b.bindSourceFileAsExternalModule()
+ // // Create symbol equivalent for the module.exports = {}
+ // originalSymbol := b.file.symbol
+ // b.declareSymbol(b.file.symbol.exports, b.file.symbol, b.file, SymbolFlagsProperty, SymbolFlagsAll)
+ // b.file.symbol = originalSymbol
+ // }
+}
+
+func (b *Binder) bindSourceFileAsExternalModule() {
+ // !!! Remove file extension from module name
+ b.bindAnonymousDeclaration(b.file.AsNode(), SymbolFlagsValueModule, "\""+b.file.fileName+"\"")
+}
+
+func (b *Binder) bindModuleDeclaration(node *Node) {
+ b.setExportContextFlag(node)
+ if isAmbientModule(node) {
+ if hasSyntacticModifier(node, ModifierFlagsExport) {
+ b.errorOnFirstToken(node, diagnostics.X_export_modifier_cannot_be_applied_to_ambient_modules_and_module_augmentations_since_they_are_always_visible)
+ }
+ if isModuleAugmentationExternal(node) {
+ b.declareModuleSymbol(node)
+ } else {
+ var pattern Pattern
+ name := node.AsModuleDeclaration().name
+ if isStringLiteral(name) {
+ pattern = tryParsePattern(name.AsStringLiteral().text)
+ if !isValidPattern(pattern) {
+ b.errorOnFirstToken(name, diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, name.AsStringLiteral().text)
+ }
+ }
+ symbol := b.declareSymbolAndAddToSymbolTable(node, SymbolFlagsValueModule, SymbolFlagsValueModuleExcludes)
+ b.file.patternAmbientModules = append(b.file.patternAmbientModules, PatternAmbientModule{pattern, symbol})
+ }
+ } else {
+ state := b.declareModuleSymbol(node)
+ if state != ModuleInstanceStateNonInstantiated {
+ symbol := node.AsModuleDeclaration().symbol
+ // if module was already merged with some function, class or non-const enum, treat it as non-const-enum-only
+ symbol.constEnumOnlyModule = symbol.constEnumOnlyModule && (symbol.flags&(SymbolFlagsFunction|SymbolFlagsClass|SymbolFlagsRegularEnum) == 0) && state == ModuleInstanceStateConstEnumOnly
+ }
+ }
+}
+
+func (b *Binder) declareModuleSymbol(node *Node) ModuleInstanceState {
+ state := getModuleInstanceState(node, nil /*visited*/)
+ instantiated := state != ModuleInstanceStateNonInstantiated
+ b.declareSymbolAndAddToSymbolTable(node, ifElse(instantiated, SymbolFlagsValueModule, SymbolFlagsNamespaceModule), ifElse(instantiated, SymbolFlagsValueModuleExcludes, SymbolFlagsNamespaceModuleExcludes))
+ return state
+}
+
+func (b *Binder) bindNamespaceExportDeclaration(node *Node) {
+ if node.AsNamespaceExportDeclaration().modifiers != nil {
+ b.errorOnNode(node, diagnostics.Modifiers_cannot_appear_here)
+ }
+ switch {
+ case !isSourceFile(node.parent):
+ b.errorOnNode(node, diagnostics.Global_module_exports_may_only_appear_at_top_level)
+ case !isExternalModule(node.parent.AsSourceFile()):
+ b.errorOnNode(node, diagnostics.Global_module_exports_may_only_appear_in_module_files)
+ case !node.parent.AsSourceFile().isDeclarationFile:
+ b.errorOnNode(node, diagnostics.Global_module_exports_may_only_appear_in_declaration_files)
+ default:
+ if b.file.symbol.globalExports == nil {
+ b.file.symbol.globalExports = make(SymbolTable)
+ }
+ b.declareSymbol(b.file.symbol.globalExports, b.file.symbol, node, SymbolFlagsAlias, SymbolFlagsAliasExcludes)
+ }
+}
+
+func (b *Binder) bindImportClause(node *Node) {
+ if node.AsImportClause().name != nil {
+ b.declareSymbolAndAddToSymbolTable(node, SymbolFlagsAlias, SymbolFlagsAliasExcludes)
+ }
+}
+
+func (b *Binder) bindExportDeclaration(node *Node) {
+ decl := node.AsExportDeclaration()
+ if b.container.Symbol() == nil {
+ // Export * in some sort of block construct
+ b.bindAnonymousDeclaration(node, SymbolFlagsExportStar, b.getDeclarationName(node))
+ } else if decl.exportClause == nil {
+ // All export * declarations are collected in an __export symbol
+ b.declareSymbol(getExports(b.container.Symbol()), b.container.Symbol(), node, SymbolFlagsExportStar, SymbolFlagsNone)
+ } else if isNamespaceExport(decl.exportClause) {
+ // declareSymbol walks up parents to find name text, parent _must_ be set
+ // but won't be set by the normal binder walk until `bindChildren` later on.
+ setParent(decl.exportClause, node)
+ b.declareSymbol(getExports(b.container.Symbol()), b.container.Symbol(), decl.exportClause, SymbolFlagsAlias, SymbolFlagsAliasExcludes)
+ }
+}
+
+func (b *Binder) bindExportAssignment(node *Node) {
+ if b.container.Symbol() == nil {
+ // Incorrect export assignment in some sort of block construct
+ b.bindAnonymousDeclaration(node, SymbolFlagsValue, b.getDeclarationName(node))
+ } else {
+ flags := SymbolFlagsProperty
+ if exportAssignmentIsAlias(node) {
+ flags = SymbolFlagsAlias
+ }
+ // If there is an `export default x;` alias declaration, can't `export default` anything else.
+ // (In contrast, you can still have `export default function f() {}` and `export default interface I {}`.)
+ symbol := b.declareSymbol(getExports(b.container.Symbol()), b.container.Symbol(), node, flags, SymbolFlagsAll)
+ if node.AsExportAssignment().isExportEquals {
+ // Will be an error later, since the module already has other exports. Just make sure this has a valueDeclaration set.
+ setValueDeclaration(symbol, node)
+ }
+ }
+}
+
+func (b *Binder) bindJsxAttributes(node *Node) {
+ b.bindAnonymousDeclaration(node, SymbolFlagsObjectLiteral, InternalSymbolNameJSXAttributes)
+}
+
+func (b *Binder) bindJsxAttribute(node *Node, symbolFlags SymbolFlags, symbolExcludes SymbolFlags) {
+ b.declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes)
+}
+
+func getModuleInstanceState(node *Node, visited map[NodeId]ModuleInstanceState) ModuleInstanceState {
+ module := node.AsModuleDeclaration()
+ if module.body != nil && module.body.parent == nil {
+ // getModuleInstanceStateForAliasTarget needs to walk up the parent chain, so parent pointers must be set on this tree already
+ setParent(module.body, node)
+ setParentInChildren(module.body)
+ }
+ if module.body != nil {
+ return getModuleInstanceStateCached(module.body, visited)
+ } else {
+ return ModuleInstanceStateInstantiated
+ }
+}
+
+func getModuleInstanceStateCached(node *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, visited)
+ visited[nodeId] = result
+ return result
+}
+
+func getModuleInstanceStateWorker(node *Node, visited map[NodeId]ModuleInstanceState) ModuleInstanceState {
+ // A module is uninstantiated if it contains only
+ switch node.kind {
+ case SyntaxKindInterfaceDeclaration, SyntaxKindTypeAliasDeclaration:
+ return ModuleInstanceStateNonInstantiated
+ case SyntaxKindEnumDeclaration:
+ if isEnumConst(node) {
+ return ModuleInstanceStateConstEnumOnly
+ }
+ case SyntaxKindImportDeclaration, SyntaxKindImportEqualsDeclaration:
+ if !hasSyntacticModifier(node, ModifierFlagsExport) {
+ return ModuleInstanceStateNonInstantiated
+ }
+ case SyntaxKindExportDeclaration:
+ decl := node.AsExportDeclaration()
+ if decl.moduleSpecifier == nil && decl.exportClause != nil && decl.exportClause.kind == SyntaxKindNamedExports {
+ state := ModuleInstanceStateNonInstantiated
+ for _, specifier := range decl.exportClause.AsNamedExports().elements {
+ specifierState := getModuleInstanceStateForAliasTarget(specifier, visited)
+ if specifierState > state {
+ state = specifierState
+ }
+ if state == ModuleInstanceStateInstantiated {
+ return state
+ }
+ }
+ return state
+ }
+ case SyntaxKindModuleBlock:
+ state := ModuleInstanceStateNonInstantiated
+ node.ForEachChild(func(n *Node) bool {
+ childState := getModuleInstanceStateCached(n, 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 SyntaxKindModuleDeclaration:
+ return getModuleInstanceState(node, visited)
+ case SyntaxKindIdentifier:
+ if node.flags&NodeFlagsIdentifierIsInJSDocNamespace != 0 {
+ return ModuleInstanceStateNonInstantiated
+ }
+ }
+ return ModuleInstanceStateInstantiated
+}
+
+func getModuleInstanceStateForAliasTarget(node *Node, visited map[NodeId]ModuleInstanceState) ModuleInstanceState {
+ spec := node.AsExportSpecifier()
+ name := spec.propertyName
+ if name == nil {
+ name = spec.name
+ }
+ if name.kind != SyntaxKindIdentifier {
+ // Skip for invalid syntax like this: export { "x" }
+ return ModuleInstanceStateInstantiated
+ }
+ for p := node.parent; p != nil; p = p.parent {
+ if isBlock(p) || isModuleBlock(p) || isSourceFile(p) {
+ statements := getStatementsOfBlock(p)
+ found := ModuleInstanceStateUnknown
+ for _, statement := range statements {
+ if nodeHasName(statement, name) {
+ if statement.parent == nil {
+ setParent(statement, p)
+ setParentInChildren(statement)
+ }
+ state := getModuleInstanceStateCached(statement, visited)
+ if found == ModuleInstanceStateUnknown || state > found {
+ found = state
+ }
+ if found == ModuleInstanceStateInstantiated {
+ return found
+ }
+ if statement.kind == SyntaxKindImportEqualsDeclaration {
+ // 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 (b *Binder) setExportContextFlag(node *Node) {
+ // A declaration source file or ambient module declaration that contains no export declarations (but possibly regular
+ // declarations with export modifiers) is an export context in which declarations are implicitly exported.
+ if node.flags&NodeFlagsAmbient != 0 && !b.hasExportDeclarations(node) {
+ node.flags |= NodeFlagsExportContext
+ } else {
+ node.flags &= ^NodeFlagsExportContext
+ }
+}
+
+func (b *Binder) hasExportDeclarations(node *Node) bool {
+ var statements []*Node
+ switch node.kind {
+ case SyntaxKindSourceFile:
+ statements = node.AsSourceFile().statements
+ case SyntaxKindModuleDeclaration:
+ body := node.AsModuleDeclaration().body
+ if isModuleBlock(body) {
+ statements = body.AsModuleBlock().statements
+ }
+ }
+ return some(statements, func(s *Node) bool {
+ return isExportDeclaration(s) || isExportAssignment(s)
+ })
+}
+
+func (b *Binder) bindFunctionExpression(node *Node) {
+ if !b.file.isDeclarationFile && node.flags&NodeFlagsAmbient == 0 && isAsyncFunction(node) {
+ b.emitFlags |= NodeFlagsHasAsyncFunctions
+ }
+ setFlowNode(node, b.currentFlow)
+ bindingName := InternalSymbolNameFunction
+ if isFunctionExpression(node) && node.AsFunctionExpression().name != nil {
+ b.checkStrictModeFunctionName(node)
+ bindingName = node.AsFunctionExpression().name.AsIdentifier().text
+ }
+ b.bindAnonymousDeclaration(node, SymbolFlagsFunction, bindingName)
+}
+
+func (b *Binder) bindClassLikeDeclaration(node *Node) {
+ name := node.ClassLikeData().name
+ switch node.kind {
+ case SyntaxKindClassDeclaration:
+ b.bindBlockScopedDeclaration(node, SymbolFlagsClass, SymbolFlagsClassExcludes)
+ case SyntaxKindClassExpression:
+ nameText := InternalSymbolNameClass
+ if name != nil {
+ nameText = name.AsIdentifier().text
+ b.classifiableNames[nameText] = true
+ }
+ b.bindAnonymousDeclaration(node, SymbolFlagsClass, nameText)
+ }
+ symbol := node.Symbol()
+ // TypeScript 1.0 spec (April 2014): 8.4
+ // Every class automatically contains a static property member named 'prototype', the
+ // type of which is an instantiation of the class type with type Any supplied as a type
+ // argument for each type parameter. It is an error to explicitly declare a static
+ // property member with the name 'prototype'.
+ //
+ // Note: we check for this here because this class may be merging into a module. The
+ // module might have an exported variable called 'prototype'. We can't allow that as
+ // that would clash with the built-in 'prototype' for the class.
+ prototypeSymbol := b.newSymbol(SymbolFlagsProperty|SymbolFlagsPrototype, "prototype")
+ symbolExport := getExports(symbol)[prototypeSymbol.name]
+ if symbolExport != nil {
+ setParent(name, node)
+ b.errorOnNode(symbolExport.declarations[0], diagnostics.Duplicate_identifier_0, symbolName(prototypeSymbol))
+ }
+ getExports(symbol)[prototypeSymbol.name] = prototypeSymbol
+ prototypeSymbol.parent = symbol
+}
+
+func (b *Binder) bindPropertyOrMethodOrAccessor(node *Node, symbolFlags SymbolFlags, symbolExcludes SymbolFlags) {
+ if !b.file.isDeclarationFile && node.flags&NodeFlagsAmbient == 0 && isAsyncFunction(node) {
+ b.emitFlags |= NodeFlagsHasAsyncFunctions
+ }
+ if b.currentFlow != nil && isObjectLiteralOrClassExpressionMethodOrAccessor(node) {
+ setFlowNode(node, b.currentFlow)
+ }
+ if hasDynamicName(node) {
+ b.bindAnonymousDeclaration(node, symbolFlags, InternalSymbolNameComputed)
+ } else {
+ b.declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes)
+ }
+}
+
+func (b *Binder) bindFunctionOrConstructorType(node *Node) {
+ // For a given function symbol "<...>(...) => T" we want to generate a symbol identical
+ // to the one we would get for: { <...>(...): T }
+ //
+ // We do that by making an anonymous type literal symbol, and then setting the function
+ // symbol as its sole member. To the rest of the system, this symbol will be indistinguishable
+ // from an actual type literal symbol you would have gotten had you used the long form.
+ symbol := b.newSymbol(SymbolFlagsSignature, b.getDeclarationName(node))
+ b.addDeclarationToSymbol(symbol, node, SymbolFlagsSignature)
+ typeLiteralSymbol := b.newSymbol(SymbolFlagsTypeLiteral, InternalSymbolNameType)
+ b.addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlagsTypeLiteral)
+ typeLiteralSymbol.members = make(SymbolTable)
+ typeLiteralSymbol.members[symbol.name] = symbol
+}
+
+func addLateBoundAssignmentDeclarationToSymbol(node *Node, symbol *Symbol) {
+ if symbol.assignmentDeclarationMembers == nil {
+ symbol.assignmentDeclarationMembers = make(map[NodeId]*Node)
+ }
+ symbol.assignmentDeclarationMembers[getNodeId(node)] = node
+}
+
+func (b *Binder) bindFunctionPropertyAssignment(node *Node) {
+ expr := node.AsBinaryExpression()
+ parentName := getAccessedExpression(expr.left).AsIdentifier().text
+ parentSymbol := b.lookupName(parentName, b.blockScopeContainer)
+ if parentSymbol == nil {
+ parentSymbol = b.lookupName(parentName, b.container)
+ }
+ if parentSymbol != nil && isFunctionSymbol(parentSymbol) {
+ // Fix up parent pointers since we're going to use these nodes before we bind into them
+ setParent(expr.left, node)
+ setParent(expr.right, node)
+ if hasDynamicName(node) {
+ b.bindAnonymousDeclaration(node, SymbolFlagsProperty|SymbolFlagsAssignment, InternalSymbolNameComputed)
+ addLateBoundAssignmentDeclarationToSymbol(node, parentSymbol)
+ } else {
+ b.declareSymbol(getExports(parentSymbol), parentSymbol, node, SymbolFlagsProperty|SymbolFlagsAssignment, SymbolFlagsPropertyExcludes)
+ }
+ }
+}
+
+func (b *Binder) bindEnumDeclaration(node *Node) {
+ if isEnumConst(node) {
+ b.bindBlockScopedDeclaration(node, SymbolFlagsConstEnum, SymbolFlagsConstEnumExcludes)
+ } else {
+ b.bindBlockScopedDeclaration(node, SymbolFlagsRegularEnum, SymbolFlagsRegularEnumExcludes)
+ }
+}
+
+func (b *Binder) bindVariableDeclarationOrBindingElement(node *Node) {
+ if b.inStrictMode {
+ b.checkStrictModeEvalOrArguments(node, node.Name())
+ }
+ if !isBindingPattern(node.Name()) {
+ switch {
+ case isBlockOrCatchScoped(node):
+ b.bindBlockScopedDeclaration(node, SymbolFlagsBlockScopedVariable, SymbolFlagsBlockScopedVariableExcludes)
+ case isPartOfParameterDeclaration(node):
+ // It is safe to walk up parent chain to find whether the node is a destructuring parameter declaration
+ // because its parent chain has already been set up, since parents are set before descending into children.
+ //
+ // If node is a binding element in parameter declaration, we need to use ParameterExcludes.
+ // Using ParameterExcludes flag allows the compiler to report an error on duplicate identifiers in Parameter Declaration
+ // For example:
+ // function foo([a,a]) {} // Duplicate Identifier error
+ // function bar(a,a) {} // Duplicate Identifier error, parameter declaration in this case is handled in bindParameter
+ // // which correctly set excluded symbols
+ b.declareSymbolAndAddToSymbolTable(node, SymbolFlagsFunctionScopedVariable, SymbolFlagsParameterExcludes)
+ default:
+ b.declareSymbolAndAddToSymbolTable(node, SymbolFlagsFunctionScopedVariable, SymbolFlagsFunctionScopedVariableExcludes)
+ }
+ }
+}
+
+func (b *Binder) bindParameter(node *Node) {
+ // !!!
+ // if node.kind == SyntaxKindJSDocParameterTag && b.container.kind != SyntaxKindJSDocSignature {
+ // return
+ // }
+ decl := node.AsParameterDeclaration()
+ if b.inStrictMode && node.flags&NodeFlagsAmbient == 9 {
+ // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a
+ // strict mode FunctionLikeDeclaration or FunctionExpression(13.1)
+ b.checkStrictModeEvalOrArguments(node, decl.name)
+ }
+ if isBindingPattern(decl.name) {
+ index := slices.Index(node.parent.FunctionLikeData().parameters, node)
+ b.bindAnonymousDeclaration(node, SymbolFlagsFunctionScopedVariable, "__"+strconv.Itoa(index))
+ } else {
+ b.declareSymbolAndAddToSymbolTable(node, SymbolFlagsFunctionScopedVariable, SymbolFlagsParameterExcludes)
+ }
+ // If this is a property-parameter, then also declare the property symbol into the
+ // containing class.
+ if isParameterPropertyDeclaration(node, node.parent) {
+ classDeclaration := node.parent.parent
+ flags := SymbolFlagsProperty | ifElse(decl.questionToken != nil, SymbolFlagsOptional, SymbolFlagsNone)
+ b.declareSymbol(getMembers(classDeclaration.Symbol()), classDeclaration.Symbol(), node, flags, SymbolFlagsPropertyExcludes)
+ }
+}
+
+func (b *Binder) bindFunctionDeclaration(node *Node) {
+ if !b.file.isDeclarationFile && node.flags&NodeFlagsAmbient == 0 && isAsyncFunction(node) {
+ b.emitFlags |= NodeFlagsHasAsyncFunctions
+ }
+ b.checkStrictModeFunctionName(node)
+ if b.inStrictMode {
+ b.checkStrictModeFunctionDeclaration(node)
+ b.bindBlockScopedDeclaration(node, SymbolFlagsFunction, SymbolFlagsFunctionExcludes)
+ } else {
+ b.declareSymbolAndAddToSymbolTable(node, SymbolFlagsFunction, SymbolFlagsFunctionExcludes)
+ }
+}
+
+func (b *Binder) getInferTypeContainer(node *Node) *Node {
+ extendsType := findAncestor(node, func(n *Node) bool {
+ parent := n.parent
+ return parent != nil && isConditionalTypeNode(parent) && parent.AsConditionalTypeNode().extendsType == n
+ })
+ if extendsType != nil {
+ return extendsType.parent
+ }
+ return nil
+}
+
+func (b *Binder) bindAnonymousDeclaration(node *Node, symbolFlags SymbolFlags, name string) {
+ symbol := b.newSymbol(symbolFlags, name)
+ if symbolFlags&(SymbolFlagsEnumMember|SymbolFlagsClassMember) != 0 {
+ symbol.parent = b.container.Symbol()
+ }
+ b.addDeclarationToSymbol(symbol, node, symbolFlags)
+}
+
+func (b *Binder) bindBlockScopedDeclaration(node *Node, symbolFlags SymbolFlags, symbolExcludes SymbolFlags) {
+ switch b.blockScopeContainer.kind {
+ case SyntaxKindModuleDeclaration:
+ b.declareModuleMember(node, symbolFlags, symbolExcludes)
+ case SyntaxKindSourceFile:
+ if isExternalOrCommonJsModule(b.container.AsSourceFile()) {
+ b.declareModuleMember(node, symbolFlags, symbolExcludes)
+ break
+ }
+ fallthrough
+ default:
+ b.declareSymbol(getLocals(b.blockScopeContainer), nil /*parent*/, node, symbolFlags, symbolExcludes)
+ }
+}
+
+func (b *Binder) bindTypeParameter(node *Node) {
+ // !!!
+ // if isJSDocTemplateTag(node.parent) {
+ // var container *HasLocals = getEffectiveContainerForJSDocTemplateTag(node.parent)
+ // if container {
+ // Debug.assertNode(container, canHaveLocals)
+ // /* TODO(TS-TO-GO) QuestionQuestionEqualsToken BinaryExpression: container.locals ??= createSymbolTable() */ TODO
+ // b.declareSymbol(container.locals /*parent*/, nil, node, SymbolFlagsTypeParameter, SymbolFlagsTypeParameterExcludes)
+ // } else {
+ // b.declareSymbolAndAddToSymbolTable(node, SymbolFlagsTypeParameter, SymbolFlagsTypeParameterExcludes)
+ // }
+ // }
+ if node.parent.kind == SyntaxKindInferType {
+ container := b.getInferTypeContainer(node.parent)
+ if container != nil {
+ b.declareSymbol(getLocals(container), nil /*parent*/, node, SymbolFlagsTypeParameter, SymbolFlagsTypeParameterExcludes)
+ } else {
+ b.bindAnonymousDeclaration(node, SymbolFlagsTypeParameter, b.getDeclarationName(node))
+ }
+ } else {
+ b.declareSymbolAndAddToSymbolTable(node, SymbolFlagsTypeParameter, SymbolFlagsTypeParameterExcludes)
+ }
+}
+
+func (b *Binder) lookupName(name string, container *Node) *Symbol {
+ data := container.LocalsContainerData()
+ if data != nil {
+ local := data.locals[name]
+ if local != nil {
+ return local
+ }
+ }
+ if isSourceFile(container) {
+ local := container.AsSourceFile().jsGlobalAugmentations[name]
+ if local != nil {
+ return local
+ }
+ }
+ symbol := container.Symbol()
+ if symbol != nil {
+ return symbol.exports[name]
+ }
+ return nil
+}
+
+// The binder visits every node in the syntax tree so it is a convenient place to perform a single localized
+// check for reserved words used as identifiers in strict mode code, as well as `yield` or `await` in
+// [Yield] or [Await] contexts, respectively.
+func (b *Binder) checkContextualIdentifier(node *Node) {
+ // Report error only if there are no parse errors in file
+ if len(b.file.diagnostics) == 0 && node.flags&NodeFlagsAmbient == 0 && node.flags&NodeFlagsJSDoc == 0 && !isIdentifierName(node) {
+ // strict mode identifiers
+ originalKeywordKind := getIdentifierToken(node.AsIdentifier().text)
+ if originalKeywordKind == SyntaxKindIdentifier {
+ return
+ }
+ if b.inStrictMode && originalKeywordKind >= SyntaxKindFirstFutureReservedWord && originalKeywordKind <= SyntaxKindLastFutureReservedWord {
+ b.errorOnNode(node, b.getStrictModeIdentifierMessage(node), declarationNameToString(node))
+ } else if originalKeywordKind == SyntaxKindAwaitKeyword {
+ if isExternalModule(b.file) && isInTopLevelContext(node) {
+ b.errorOnNode(node, diagnostics.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module, declarationNameToString(node))
+ } else if node.flags&NodeFlagsAwaitContext != 0 {
+ b.errorOnNode(node, diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, declarationNameToString(node))
+ }
+ } else if originalKeywordKind == SyntaxKindYieldKeyword && node.flags&NodeFlagsYieldContext != 0 {
+ b.errorOnNode(node, diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, declarationNameToString(node))
+ }
+ }
+}
+
+func (b *Binder) checkPrivateIdentifier(node *Node) {
+ if node.AsPrivateIdentifier().text == "#constructor" {
+ // Report error only if there are no parse errors in file
+ if len(b.file.diagnostics) == 0 {
+ b.errorOnNode(node, diagnostics.X_constructor_is_a_reserved_word, declarationNameToString(node))
+ }
+ }
+}
+
+func (b *Binder) getStrictModeIdentifierMessage(node *Node) *diagnostics.Message {
+ // Provide specialized messages to help the user understand why we think they're in
+ // strict mode.
+ if getContainingClass(node) != nil {
+ return diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode
+ }
+ if b.file.externalModuleIndicator != nil {
+ return diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode
+ }
+ return diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode
+}
+
+func (b *Binder) updateStrictModeStatementList(statements []*Node) {
+ if !b.inStrictMode {
+ for _, statement := range statements {
+ if !isPrologueDirective(statement) {
+ return
+ }
+ if b.isUseStrictPrologueDirective(statement) {
+ b.inStrictMode = true
+ return
+ }
+ }
+ }
+}
+
+// Should be called only on prologue directives (isPrologueDirective(node) should be true)
+func (b *Binder) isUseStrictPrologueDirective(node *Node) bool {
+ nodeText := getSourceTextOfNodeFromSourceFile(b.file, node.AsExpressionStatement().expression)
+ // Note: the node text must be exactly "use strict" or 'use strict'. It is not ok for the
+ // string to contain unicode escapes (as per ES5).
+ return nodeText == "\"use strict\"" || nodeText == "'use strict'"
+}
+
+func (b *Binder) checkStrictModeFunctionName(node *Node) {
+ if b.inStrictMode && node.flags&NodeFlagsAmbient == 0 {
+ // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression (13.1))
+ b.checkStrictModeEvalOrArguments(node, node.Name())
+ }
+}
+
+func (b *Binder) checkStrictModeFunctionDeclaration(node *Node) {
+ if b.languageVersion < ScriptTargetES2015 {
+ // Report error if function is not top level function declaration
+ if b.blockScopeContainer.kind != SyntaxKindSourceFile && b.blockScopeContainer.kind != SyntaxKindModuleDeclaration && !isFunctionLikeOrClassStaticBlockDeclaration(b.blockScopeContainer) {
+ // We check first if the name is inside class declaration or class expression; if so give explicit message
+ // otherwise report generic error message.
+ b.errorOnNode(node, b.getStrictModeBlockScopeFunctionDeclarationMessage(node))
+ }
+ }
+}
+
+func (b *Binder) getStrictModeBlockScopeFunctionDeclarationMessage(node *Node) *diagnostics.Message {
+ // Provide specialized messages to help the user understand why we think they're in strict mode.
+ if getContainingClass(node) != nil {
+ return diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES5_Class_definitions_are_automatically_in_strict_mode
+ }
+ if b.file.externalModuleIndicator != nil {
+ return diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES5_Modules_are_automatically_in_strict_mode
+ }
+ return diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES5
+}
+
+func (b *Binder) checkStrictModeBinaryExpression(node *Node) {
+ expr := node.AsBinaryExpression()
+ if b.inStrictMode && isLeftHandSideExpression(expr.left) && isAssignmentOperator(expr.operatorToken.kind) {
+ // ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an
+ // Assignment operator(11.13) or of a PostfixExpression(11.3)
+ b.checkStrictModeEvalOrArguments(node, expr.left)
+ }
+}
+
+func (b *Binder) checkStrictModeCatchClause(node *Node) {
+ // It is a SyntaxError if a TryStatement with a Catch occurs within strict code and the Identifier of the
+ // Catch production is eval or arguments
+ clause := node.AsCatchClause()
+ if b.inStrictMode && clause.variableDeclaration != nil {
+ b.checkStrictModeEvalOrArguments(node, clause.variableDeclaration.AsVariableDeclaration().name)
+ }
+}
+
+func (b *Binder) checkStrictModeDeleteExpression(node *Node) {
+ // Grammar checking
+ expr := node.AsDeleteExpression()
+ if b.inStrictMode && expr.expression.kind == SyntaxKindIdentifier {
+ // When a delete operator occurs within strict mode code, a SyntaxError is thrown if its
+ // UnaryExpression is a direct reference to a variable, function argument, or function name
+ b.errorOnNode(expr.expression, diagnostics.X_delete_cannot_be_called_on_an_identifier_in_strict_mode)
+ }
+}
+
+func (b *Binder) checkStrictModePostfixUnaryExpression(node *Node) {
+ // Grammar checking
+ // The identifier eval or arguments may not appear as the LeftHandSideExpression of an
+ // Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression
+ // operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator.
+ if b.inStrictMode {
+ b.checkStrictModeEvalOrArguments(node, node.AsPostfixUnaryExpression().operand)
+ }
+}
+
+func (b *Binder) checkStrictModePrefixUnaryExpression(node *Node) {
+ // Grammar checking
+ if b.inStrictMode {
+ expr := node.AsPrefixUnaryExpression()
+ if expr.operator == SyntaxKindPlusPlusToken || expr.operator == SyntaxKindMinusMinusToken {
+ b.checkStrictModeEvalOrArguments(node, expr.operand)
+ }
+ }
+}
+
+func (b *Binder) checkStrictModeWithStatement(node *Node) {
+ // Grammar checking for withStatement
+ if b.inStrictMode {
+ b.errorOnFirstToken(node, diagnostics.X_with_statements_are_not_allowed_in_strict_mode)
+ }
+}
+
+func (b *Binder) checkStrictModeLabeledStatement(node *Node) {
+ // Grammar checking for labeledStatement
+ if b.inStrictMode && b.options.Target >= ScriptTargetES2015 {
+ data := node.AsLabeledStatement()
+ if isDeclarationStatement(data.statement) || isVariableStatement(data.statement) {
+ b.errorOnFirstToken(data.label, diagnostics.A_label_is_not_allowed_here)
+ }
+ }
+}
+
+func isEvalOrArgumentsIdentifier(node *Node) bool {
+ if isIdentifier(node) {
+ text := node.AsIdentifier().text
+ return text == "eval" || text == "arguments"
+ }
+ return false
+}
+
+func (b *Binder) checkStrictModeEvalOrArguments(contextNode *Node, name *Node) {
+ if name != nil && isEvalOrArgumentsIdentifier(name) {
+ // We check first if the name is inside class declaration or class expression; if so give explicit message
+ // otherwise report generic error message.
+ b.errorOnNode(name, b.getStrictModeEvalOrArgumentsMessage(contextNode), name.AsIdentifier().text)
+ }
+}
+
+func (b *Binder) getStrictModeEvalOrArgumentsMessage(node *Node) *diagnostics.Message {
+ // Provide specialized messages to help the user understand why we think they're in strict mode
+ if getContainingClass(node) != nil {
+ return diagnostics.Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode
+ }
+ if b.file.externalModuleIndicator != nil {
+ return diagnostics.Invalid_use_of_0_Modules_are_automatically_in_strict_mode
+ }
+ return diagnostics.Invalid_use_of_0_in_strict_mode
+}
+
+// All container nodes are kept on a linked list in declaration order. This list is used by
+// the getLocalNameOfContainer function in the type checker to validate that the local name
+// used for a container is unique.
+func (b *Binder) bindContainer(node *Node, containerFlags ContainerFlags) {
+ // Before we recurse into a node's children, we first save the existing parent, container
+ // and block-container. Then after we pop out of processing the children, we restore
+ // these saved values.
+ saveContainer := b.container
+ saveThisParentContainer := b.thisParentContainer
+ savedBlockScopeContainer := b.blockScopeContainer
+ // Depending on what kind of node this is, we may have to adjust the current container
+ // and block-container. If the current node is a container, then it is automatically
+ // considered the current block-container as well. Also, for containers that we know
+ // may contain locals, we eagerly initialize the .locals field. We do this because
+ // it's highly likely that the .locals will be needed to place some child in (for example,
+ // a parameter, or variable declaration).
+ //
+ // However, we do not proactively create the .locals for block-containers because it's
+ // totally normal and common for block-containers to never actually have a block-scoped
+ // variable in them. We don't want to end up allocating an object for every 'block' we
+ // run into when most of them won't be necessary.
+ //
+ // Finally, if this is a block-container, then we clear out any existing .locals object
+ // it may contain within it. This happens in incremental scenarios. Because we can be
+ // reusing a node from a previous compilation, that node may have had 'locals' created
+ // for it. We must clear this so we don't accidentally move any stale data forward from
+ // a previous compilation.
+ if containerFlags&ContainerFlagsIsContainer != 0 {
+ if node.kind != SyntaxKindArrowFunction {
+ b.thisParentContainer = b.container
+ }
+ b.container = node
+ b.blockScopeContainer = node
+ if containerFlags&ContainerFlagsHasLocals != 0 {
+ // localsContainer := node
+ // localsContainer.LocalsContainerData().locals = make(SymbolTable)
+ b.addToContainerChain(node)
+ }
+ } else if containerFlags&ContainerFlagsIsBlockScopedContainer != 0 {
+ b.blockScopeContainer = node
+ b.addToContainerChain(node)
+ }
+ if containerFlags&ContainerFlagsIsControlFlowContainer != 0 {
+ saveCurrentFlow := b.currentFlow
+ saveBreakTarget := b.currentBreakTarget
+ saveContinueTarget := b.currentContinueTarget
+ saveReturnTarget := b.currentReturnTarget
+ saveExceptionTarget := b.currentExceptionTarget
+ saveActiveLabelList := b.activeLabelList
+ saveHasExplicitReturn := b.hasExplicitReturn
+ isImmediatelyInvoked := (containerFlags&ContainerFlagsIsFunctionExpression != 0 &&
+ !hasSyntacticModifier(node, ModifierFlagsAsync) &&
+ !isGeneratorFunctionExpression(node) &&
+ getImmediatelyInvokedFunctionExpression(node) != nil) || node.kind == SyntaxKindClassStaticBlockDeclaration
+ // A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave
+ // similarly to break statements that exit to a label just past the statement body.
+ if !isImmediatelyInvoked {
+ flowStart := b.newFlowNode(FlowFlagsStart)
+ b.currentFlow = flowStart
+ if containerFlags&(ContainerFlagsIsFunctionExpression|ContainerFlagsIsObjectLiteralOrClassExpressionMethodOrAccessor) != 0 {
+ flowStart.node = node
+ }
+ }
+ // We create a return control flow graph for IIFEs and constructors. For constructors
+ // we use the return control flow graph in strict property initialization checks.
+ if isImmediatelyInvoked || node.kind == SyntaxKindConstructor {
+ b.currentReturnTarget = b.newFlowNode(FlowFlagsBranchLabel)
+ } else {
+ b.currentReturnTarget = nil
+ }
+ b.currentExceptionTarget = nil
+ b.currentBreakTarget = nil
+ b.currentContinueTarget = nil
+ b.activeLabelList = nil
+ b.hasExplicitReturn = false
+ b.bindChildren(node)
+ // Reset all reachability check related flags on node (for incremental scenarios)
+ node.flags &= ^NodeFlagsReachabilityAndEmitFlags
+ if b.currentFlow.flags&FlowFlagsUnreachable == 0 && containerFlags&ContainerFlagsIsFunctionLike != 0 {
+ bodyData := node.BodyData()
+ if bodyData != nil && nodeIsPresent(bodyData.body) {
+ node.flags |= NodeFlagsHasImplicitReturn
+ if b.hasExplicitReturn {
+ node.flags |= NodeFlagsHasExplicitReturn
+ }
+ bodyData.endFlowNode = b.currentFlow
+ }
+ }
+ if node.kind == SyntaxKindSourceFile {
+ node.flags |= b.emitFlags
+ node.AsSourceFile().endFlowNode = b.currentFlow
+ }
+
+ if b.currentReturnTarget != nil {
+ b.addAntecedent(b.currentReturnTarget, b.currentFlow)
+ b.currentFlow = finishFlowLabel(b.currentReturnTarget)
+ if node.kind == SyntaxKindConstructor || node.kind == SyntaxKindClassStaticBlockDeclaration {
+ setReturnFlowNode(node, b.currentFlow)
+ }
+ }
+ if !isImmediatelyInvoked {
+ b.currentFlow = saveCurrentFlow
+ }
+ b.currentBreakTarget = saveBreakTarget
+ b.currentContinueTarget = saveContinueTarget
+ b.currentReturnTarget = saveReturnTarget
+ b.currentExceptionTarget = saveExceptionTarget
+ b.activeLabelList = saveActiveLabelList
+ b.hasExplicitReturn = saveHasExplicitReturn
+ } else if containerFlags&ContainerFlagsIsInterface != 0 {
+ b.seenThisKeyword = false
+ b.bindChildren(node)
+ // ContainsThis cannot overlap with HasExtendedUnicodeEscape on Identifier
+ if b.seenThisKeyword {
+ node.flags |= NodeFlagsContainsThis
+ } else {
+ node.flags &= ^NodeFlagsContainsThis
+ }
+ } else {
+ b.bindChildren(node)
+ }
+ b.container = saveContainer
+ b.thisParentContainer = saveThisParentContainer
+ b.blockScopeContainer = savedBlockScopeContainer
+}
+
+func (b *Binder) bindChildren(node *Node) {
+ saveInAssignmentPattern := b.inAssignmentPattern
+ // Most nodes aren't valid in an assignment pattern, so we clear the value here
+ // and set it before we descend into nodes that could actually be part of an assignment pattern.
+ b.inAssignmentPattern = false
+ if b.checkUnreachable(node) {
+ b.bindEachChild(node)
+ b.inAssignmentPattern = saveInAssignmentPattern
+ return
+ }
+ kind := node.kind
+ if kind >= SyntaxKindFirstStatement && kind <= SyntaxKindLastStatement && (b.options.AllowUnreachableCode != TSTrue || kind == SyntaxKindReturnStatement) {
+ hasFlowNodeData := node.FlowNodeData()
+ if hasFlowNodeData != nil {
+ hasFlowNodeData.flowNode = b.currentFlow
+ }
+ }
+ switch node.kind {
+ case SyntaxKindWhileStatement:
+ b.bindWhileStatement(node)
+ case SyntaxKindDoStatement:
+ b.bindDoStatement(node)
+ case SyntaxKindForStatement:
+ b.bindForStatement(node)
+ case SyntaxKindForInStatement, SyntaxKindForOfStatement:
+ b.bindForInOrForOfStatement(node)
+ case SyntaxKindIfStatement:
+ b.bindIfStatement(node)
+ case SyntaxKindReturnStatement:
+ b.bindReturnStatement(node)
+ case SyntaxKindThrowStatement:
+ b.bindThrowStatement(node)
+ case SyntaxKindBreakStatement:
+ b.bindBreakStatement(node)
+ case SyntaxKindContinueStatement:
+ b.bindContinueStatement(node)
+ case SyntaxKindTryStatement:
+ b.bindTryStatement(node)
+ case SyntaxKindSwitchStatement:
+ b.bindSwitchStatement(node)
+ case SyntaxKindCaseBlock:
+ b.bindCaseBlock(node)
+ case SyntaxKindCaseClause, SyntaxKindDefaultClause:
+ b.bindCaseOrDefaultClause(node)
+ case SyntaxKindExpressionStatement:
+ b.bindExpressionStatement(node)
+ case SyntaxKindLabeledStatement:
+ b.bindLabeledStatement(node)
+ case SyntaxKindPrefixUnaryExpression:
+ b.bindPrefixUnaryExpressionFlow(node)
+ case SyntaxKindPostfixUnaryExpression:
+ b.bindPostfixUnaryExpressionFlow(node)
+ case SyntaxKindBinaryExpression:
+ if isDestructuringAssignment(node) {
+ // Carry over whether we are in an assignment pattern to
+ // binary expressions that could actually be an initializer
+ b.inAssignmentPattern = saveInAssignmentPattern
+ b.bindDestructuringAssignmentFlow(node)
+ return
+ }
+ b.bindBinaryExpressionFlow(node)
+ case SyntaxKindDeleteExpression:
+ b.bindDeleteExpressionFlow(node)
+ case SyntaxKindConditionalExpression:
+ b.bindConditionalExpressionFlow(node)
+ case SyntaxKindVariableDeclaration:
+ b.bindVariableDeclarationFlow(node)
+ case SyntaxKindPropertyAccessExpression, SyntaxKindElementAccessExpression:
+ b.bindAccessExpressionFlow(node)
+ case SyntaxKindCallExpression:
+ b.bindCallExpressionFlow(node)
+ case SyntaxKindNonNullExpression:
+ b.bindNonNullExpressionFlow(node)
+ // case *JSDocTypedefTag, *JSDocCallbackTag, *JSDocEnumTag:
+ // b.bindJSDocTypeAlias(node)
+ // case *JSDocImportTag:
+ // b.bindJSDocImportTag(node)
+ case SyntaxKindSourceFile:
+ b.bindEachStatementFunctionsFirst(node.AsSourceFile().statements)
+ //b.bind(node.endOfFileToken)
+ case SyntaxKindBlock:
+ b.bindEachStatementFunctionsFirst(node.AsBlock().statements)
+ case SyntaxKindModuleBlock:
+ b.bindEachStatementFunctionsFirst(node.AsModuleBlock().statements)
+ case SyntaxKindBindingElement:
+ b.bindBindingElementFlow(node)
+ case SyntaxKindParameter:
+ b.bindParameterFlow(node)
+ case SyntaxKindObjectLiteralExpression, SyntaxKindArrayLiteralExpression, SyntaxKindPropertyAssignment, SyntaxKindSpreadElement:
+ b.inAssignmentPattern = saveInAssignmentPattern
+ b.bindEachChild(node)
+ default:
+ b.bindEachChild(node)
+ }
+ b.inAssignmentPattern = saveInAssignmentPattern
+}
+
+func (b *Binder) bindEachChild(node *Node) {
+ node.ForEachChild(b.bind)
+}
+
+func (b *Binder) bindEachExpression(nodes []*Node) {
+ for _, node := range nodes {
+ b.bind(node)
+ }
+}
+
+func (b *Binder) bindEachStatement(nodes []*Node) {
+ for _, node := range nodes {
+ b.bind(node)
+ }
+}
+
+func (b *Binder) bindEachStatementFunctionsFirst(statements []*Node) {
+ for _, node := range statements {
+ if node.kind == SyntaxKindFunctionDeclaration {
+ b.bind(node)
+ }
+ }
+ for _, node := range statements {
+ if node.kind != SyntaxKindFunctionDeclaration {
+ b.bind(node)
+ }
+ }
+}
+
+func (b *Binder) checkUnreachable(node *Node) bool {
+ if b.currentFlow.flags&FlowFlagsUnreachable == 0 {
+ return false
+ }
+ if b.currentFlow == unreachableFlow {
+ // report errors on all statements except empty ones
+ // report errors on class declarations
+ // report errors on enums with preserved emit
+ // report errors on instantiated modules
+ reportError := isStatementButNotDeclaration(node) && !isEmptyStatement(node) ||
+ isClassDeclaration(node) ||
+ isEnumDeclarationWithPreservedEmit(node, b.options) ||
+ isModuleDeclaration(node) && b.shouldReportErrorOnModuleDeclaration(node)
+ if reportError {
+ b.currentFlow = reportedUnreachableFlow
+ if b.options.AllowUnreachableCode != TSTrue {
+ // unreachable code is reported if
+ // - user has explicitly asked about it AND
+ // - statement is in not ambient context (statements in ambient context is already an error
+ // so we should not report extras) AND
+ // - node is not variable statement OR
+ // - node is block scoped variable statement OR
+ // - node is not block scoped variable statement and at least one variable declaration has initializer
+ // Rationale: we don't want to report errors on non-initialized var's since they are hoisted
+ // On the other side we do want to report errors on non-initialized 'lets' because of TDZ
+ isError := unreachableCodeIsError(b.options) && node.flags&NodeFlagsAmbient == 0 && (!isVariableStatement(node) ||
+ getCombinedNodeFlags(node.AsVariableStatement().declarationList)&NodeFlagsBlockScoped != 0 ||
+ some(node.AsVariableStatement().declarationList.AsVariableDeclarationList().declarations, func(d *Node) bool {
+ return d.AsVariableDeclaration().initializer != nil
+ }))
+ b.errorOnEachUnreachableRange(node, isError)
+ }
+ }
+ }
+ return true
+}
+
+func (b *Binder) shouldReportErrorOnModuleDeclaration(node *Node) bool {
+ instanceState := getModuleInstanceState(node, nil /*visited*/)
+ return instanceState == ModuleInstanceStateInstantiated || (instanceState == ModuleInstanceStateConstEnumOnly && shouldPreserveConstEnums(b.options))
+}
+
+func (b *Binder) errorOnEachUnreachableRange(node *Node, isError bool) {
+ if b.isExecutableStatement(node) && isBlock(node.parent) {
+ statements := node.parent.AsBlock().statements
+ index := slices.Index(statements, node)
+ var first, last *Node
+ for _, s := range statements[index:] {
+ if b.isExecutableStatement(s) {
+ if first == nil {
+ first = s
+ }
+ last = s
+ } else if first != nil {
+ b.errorOrSuggestionOnRange(isError, first, last, diagnostics.Unreachable_code_detected)
+ first = nil
+ }
+ }
+ if first != nil {
+ b.errorOrSuggestionOnRange(isError, first, last, diagnostics.Unreachable_code_detected)
+ }
+ } else {
+ b.errorOrSuggestionOnNode(isError, node, diagnostics.Unreachable_code_detected)
+ }
+}
+
+// As opposed to a pure declaration like an `interface`
+func (b *Binder) isExecutableStatement(s *Node) bool {
+ // Don't remove statements that can validly be used before they appear.
+ return !isFunctionDeclaration(s) && !b.isPurelyTypeDeclaration(s) && !(isVariableStatement(s) && getCombinedNodeFlags(s)&NodeFlagsBlockScoped == 0 &&
+ some(s.AsVariableStatement().declarationList.AsVariableDeclarationList().declarations, func(d *Node) bool {
+ return d.AsVariableDeclaration().initializer == nil
+ }))
+}
+
+func (b *Binder) isPurelyTypeDeclaration(s *Node) bool {
+ switch s.kind {
+ case SyntaxKindInterfaceDeclaration, SyntaxKindTypeAliasDeclaration:
+ return true
+ case SyntaxKindModuleDeclaration:
+ return getModuleInstanceState(s, nil /*visited*/) != ModuleInstanceStateInstantiated
+ case SyntaxKindEnumDeclaration:
+ return !isEnumDeclarationWithPreservedEmit(s, b.options)
+ default:
+ return false
+ }
+}
+
+func (b *Binder) setContinueTarget(node *Node, target *FlowLabel) *FlowLabel {
+ label := b.activeLabelList
+ for label != nil && node.parent.kind == SyntaxKindLabeledStatement {
+ label.continueTarget = target
+ label = label.next
+ node = node.parent
+ }
+ return target
+}
+
+func (b *Binder) doWithConditionalBranches(action func(value *Node) bool, value *Node, trueTarget *FlowLabel, falseTarget *FlowLabel) {
+ savedTrueTarget := b.currentTrueTarget
+ savedFalseTarget := b.currentFalseTarget
+ b.currentTrueTarget = trueTarget
+ b.currentFalseTarget = falseTarget
+ action(value)
+ b.currentTrueTarget = savedTrueTarget
+ b.currentFalseTarget = savedFalseTarget
+}
+
+func (b *Binder) bindCondition(node *Node, trueTarget *FlowLabel, falseTarget *FlowLabel) {
+ b.doWithConditionalBranches(b.bind, node, trueTarget, falseTarget)
+ if node == nil || !isLogicalAssignmentExpression(node) && !isLogicalExpression(node) && !(isOptionalChain(node) && isOutermostOptionalChain(node)) {
+ b.addAntecedent(trueTarget, b.createFlowCondition(FlowFlagsTrueCondition, b.currentFlow, node))
+ b.addAntecedent(falseTarget, b.createFlowCondition(FlowFlagsFalseCondition, b.currentFlow, node))
+ }
+}
+
+func (b *Binder) bindIterativeStatement(node *Node, breakTarget *FlowLabel, continueTarget *FlowLabel) {
+ saveBreakTarget := b.currentBreakTarget
+ saveContinueTarget := b.currentContinueTarget
+ b.currentBreakTarget = breakTarget
+ b.currentContinueTarget = continueTarget
+ b.bind(node)
+ b.currentBreakTarget = saveBreakTarget
+ b.currentContinueTarget = saveContinueTarget
+}
+
+func isLogicalAssignmentExpression(node *Node) bool {
+ return isLogicalOrCoalescingAssignmentExpression(skipParentheses(node))
+}
+
+func (b *Binder) bindAssignmentTargetFlow(node *Node) {
+ switch node.kind {
+ case SyntaxKindArrayLiteralExpression:
+ for _, e := range node.AsArrayLiteralExpression().elements {
+ if e.kind == SyntaxKindSpreadElement {
+ b.bindAssignmentTargetFlow(e.AsSpreadElement().expression)
+ } else {
+ b.bindDestructuringTargetFlow(e)
+ }
+ }
+ case SyntaxKindObjectLiteralExpression:
+ for _, p := range node.AsObjectLiteralExpression().properties {
+ switch p.kind {
+ case SyntaxKindPropertyAssignment:
+ b.bindDestructuringTargetFlow(p.AsPropertyAssignment().initializer)
+ case SyntaxKindShorthandPropertyAssignment:
+ b.bindAssignmentTargetFlow(p.AsShorthandPropertyAssignment().name)
+ case SyntaxKindSpreadAssignment:
+ b.bindAssignmentTargetFlow(p.AsSpreadAssignment().expression)
+ }
+ }
+ default:
+ if isNarrowableReference(node) {
+ b.currentFlow = b.createFlowMutation(FlowFlagsAssignment, b.currentFlow, node)
+ }
+ }
+}
+
+func (b *Binder) bindDestructuringTargetFlow(node *Node) {
+ if isBinaryExpression(node) && node.AsBinaryExpression().operatorToken.kind == SyntaxKindEqualsToken {
+ b.bindAssignmentTargetFlow(node.AsBinaryExpression().left)
+ } else {
+ b.bindAssignmentTargetFlow(node)
+ }
+}
+
+func (b *Binder) bindWhileStatement(node *Node) {
+ stmt := node.AsWhileStatement()
+ preWhileLabel := b.setContinueTarget(node, b.createLoopLabel())
+ preBodyLabel := b.createBranchLabel()
+ postWhileLabel := b.createBranchLabel()
+ b.addAntecedent(preWhileLabel, b.currentFlow)
+ b.currentFlow = preWhileLabel
+ b.bindCondition(stmt.expression, preBodyLabel, postWhileLabel)
+ b.currentFlow = finishFlowLabel(preBodyLabel)
+ b.bindIterativeStatement(stmt.statement, postWhileLabel, preWhileLabel)
+ b.addAntecedent(preWhileLabel, b.currentFlow)
+ b.currentFlow = finishFlowLabel(postWhileLabel)
+}
+
+func (b *Binder) bindDoStatement(node *Node) {
+ stmt := node.AsDoStatement()
+ preDoLabel := b.createLoopLabel()
+ preConditionLabel := b.setContinueTarget(node, b.createBranchLabel())
+ postDoLabel := b.createBranchLabel()
+ b.addAntecedent(preDoLabel, b.currentFlow)
+ b.currentFlow = preDoLabel
+ b.bindIterativeStatement(stmt.statement, postDoLabel, preConditionLabel)
+ b.addAntecedent(preConditionLabel, b.currentFlow)
+ b.currentFlow = finishFlowLabel(preConditionLabel)
+ b.bindCondition(stmt.expression, preDoLabel, postDoLabel)
+ b.currentFlow = finishFlowLabel(postDoLabel)
+}
+
+func (b *Binder) bindForStatement(node *Node) {
+ stmt := node.AsForStatement()
+ preLoopLabel := b.setContinueTarget(node, b.createLoopLabel())
+ preBodyLabel := b.createBranchLabel()
+ postLoopLabel := b.createBranchLabel()
+ b.bind(stmt.initializer)
+ b.addAntecedent(preLoopLabel, b.currentFlow)
+ b.currentFlow = preLoopLabel
+ b.bindCondition(stmt.condition, preBodyLabel, postLoopLabel)
+ b.currentFlow = finishFlowLabel(preBodyLabel)
+ b.bindIterativeStatement(stmt.statement, postLoopLabel, preLoopLabel)
+ b.bind(stmt.incrementor)
+ b.addAntecedent(preLoopLabel, b.currentFlow)
+ b.currentFlow = finishFlowLabel(postLoopLabel)
+}
+
+func (b *Binder) bindForInOrForOfStatement(node *Node) {
+ stmt := node.AsForInOrOfStatement()
+ preLoopLabel := b.setContinueTarget(node, b.createLoopLabel())
+ postLoopLabel := b.createBranchLabel()
+ b.bind(stmt.expression)
+ b.addAntecedent(preLoopLabel, b.currentFlow)
+ b.currentFlow = preLoopLabel
+ if node.kind == SyntaxKindForOfStatement {
+ b.bind(stmt.awaitModifier)
+ }
+ b.addAntecedent(postLoopLabel, b.currentFlow)
+ b.bind(stmt.initializer)
+ if stmt.initializer.kind != SyntaxKindVariableDeclarationList {
+ b.bindAssignmentTargetFlow(stmt.initializer)
+ }
+ b.bindIterativeStatement(stmt.statement, postLoopLabel, preLoopLabel)
+ b.addAntecedent(preLoopLabel, b.currentFlow)
+ b.currentFlow = finishFlowLabel(postLoopLabel)
+}
+
+func (b *Binder) bindIfStatement(node *Node) {
+ stmt := node.AsIfStatement()
+ thenLabel := b.createBranchLabel()
+ elseLabel := b.createBranchLabel()
+ postIfLabel := b.createBranchLabel()
+ b.bindCondition(stmt.expression, thenLabel, elseLabel)
+ b.currentFlow = finishFlowLabel(thenLabel)
+ b.bind(stmt.thenStatement)
+ b.addAntecedent(postIfLabel, b.currentFlow)
+ b.currentFlow = finishFlowLabel(elseLabel)
+ b.bind(stmt.elseStatement)
+ b.addAntecedent(postIfLabel, b.currentFlow)
+ b.currentFlow = finishFlowLabel(postIfLabel)
+}
+
+func (b *Binder) bindReturnStatement(node *Node) {
+ b.bind(node.AsReturnStatement().expression)
+ if b.currentReturnTarget != nil {
+ b.addAntecedent(b.currentReturnTarget, b.currentFlow)
+ }
+ b.currentFlow = unreachableFlow
+ b.hasExplicitReturn = true
+ b.hasFlowEffects = true
+}
+
+func (b *Binder) bindThrowStatement(node *Node) {
+ b.bind(node.AsThrowStatement().expression)
+ b.currentFlow = unreachableFlow
+ b.hasFlowEffects = true
+}
+
+func (b *Binder) bindBreakStatement(node *Node) {
+ b.bindBreakOrContinueStatement(node.AsBreakStatement().label, b.currentBreakTarget, (*ActiveLabel).BreakTarget)
+}
+
+func (b *Binder) bindContinueStatement(node *Node) {
+ b.bindBreakOrContinueStatement(node.AsContinueStatement().label, b.currentContinueTarget, (*ActiveLabel).ContinueTarget)
+}
+
+func (b *Binder) bindBreakOrContinueStatement(label *Node, currentTarget *FlowNode, getTarget func(*ActiveLabel) *FlowNode) {
+ b.bind(label)
+ if label != nil {
+ activeLabel := b.findActiveLabel(label.AsIdentifier().text)
+ if activeLabel != nil {
+ activeLabel.referenced = true
+ b.bindBreakOrContinueFlow(getTarget(activeLabel))
+ }
+ } else {
+ b.bindBreakOrContinueFlow(currentTarget)
+ }
+}
+
+func (b *Binder) findActiveLabel(name string) *ActiveLabel {
+ for label := b.activeLabelList; label != nil; label = label.next {
+ if label.name == name {
+ return label
+ }
+ }
+ return nil
+}
+
+func (b *Binder) bindBreakOrContinueFlow(flowLabel *FlowLabel) {
+ if flowLabel != nil {
+ b.addAntecedent(flowLabel, b.currentFlow)
+ b.currentFlow = unreachableFlow
+ b.hasFlowEffects = true
+ }
+}
+
+func (b *Binder) bindTryStatement(node *Node) {
+ // We conservatively assume that *any* code in the try block can cause an exception, but we only need
+ // to track code that causes mutations (because only mutations widen the possible control flow type of
+ // a variable). The exceptionLabel is the target label for control flows that result from exceptions.
+ // We add all mutation flow nodes as antecedents of this label such that we can analyze them as possible
+ // antecedents of the start of catch or finally blocks. Furthermore, we add the current control flow to
+ // represent exceptions that occur before any mutations.
+ stmt := node.AsTryStatement()
+ saveReturnTarget := b.currentReturnTarget
+ saveExceptionTarget := b.currentExceptionTarget
+ normalExitLabel := b.createBranchLabel()
+ returnLabel := b.createBranchLabel()
+ exceptionLabel := b.createBranchLabel()
+ if stmt.finallyBlock != nil {
+ b.currentReturnTarget = returnLabel
+ }
+ b.addAntecedent(exceptionLabel, b.currentFlow)
+ b.currentExceptionTarget = exceptionLabel
+ b.bind(stmt.tryBlock)
+ b.addAntecedent(normalExitLabel, b.currentFlow)
+ if stmt.catchClause != nil {
+ // Start of catch clause is the target of exceptions from try block.
+ b.currentFlow = finishFlowLabel(exceptionLabel)
+ // The currentExceptionTarget now represents control flows from exceptions in the catch clause.
+ // Effectively, in a try-catch-finally, if an exception occurs in the try block, the catch block
+ // acts like a second try block.
+ exceptionLabel = b.createBranchLabel()
+ b.addAntecedent(exceptionLabel, b.currentFlow)
+ b.currentExceptionTarget = exceptionLabel
+ b.bind(stmt.catchClause)
+ b.addAntecedent(normalExitLabel, b.currentFlow)
+ }
+ b.currentReturnTarget = saveReturnTarget
+ b.currentExceptionTarget = saveExceptionTarget
+ if stmt.finallyBlock != nil {
+ // Possible ways control can reach the finally block:
+ // 1) Normal completion of try block of a try-finally or try-catch-finally
+ // 2) Normal completion of catch block (following exception in try block) of a try-catch-finally
+ // 3) Return in try or catch block of a try-finally or try-catch-finally
+ // 4) Exception in try block of a try-finally
+ // 5) Exception in catch block of a try-catch-finally
+ // When analyzing a control flow graph that starts inside a finally block we want to consider all
+ // five possibilities above. However, when analyzing a control flow graph that starts outside (past)
+ // the finally block, we only want to consider the first two (if we're past a finally block then it
+ // must have completed normally). Likewise, when analyzing a control flow graph from return statements
+ // in try or catch blocks in an IIFE, we only want to consider the third. To make this possible, we
+ // inject a ReduceLabel node into the control flow graph. This node contains an alternate reduced
+ // set of antecedents for the pre-finally label. As control flow analysis passes by a ReduceLabel
+ // node, the pre-finally label is temporarily switched to the reduced antecedent set.
+ finallyLabel := b.createBranchLabel()
+ finallyLabel.antecedents = b.combineFlowLists(normalExitLabel.antecedents, b.combineFlowLists(exceptionLabel.antecedents, returnLabel.antecedents))
+ b.currentFlow = finallyLabel
+ b.bind(stmt.finallyBlock)
+ if b.currentFlow.flags&FlowFlagsUnreachable != 0 {
+ // If the end of the finally block is unreachable, the end of the entire try statement is unreachable.
+ b.currentFlow = unreachableFlow
+ } else {
+ // If we have an IIFE return target and return statements in the try or catch blocks, add a control
+ // flow that goes back through the finally block and back through only the return statements.
+ if b.currentReturnTarget != nil && returnLabel.antecedent != nil {
+ b.addAntecedent(b.currentReturnTarget, b.createReduceLabel(finallyLabel, returnLabel.antecedents, b.currentFlow))
+ }
+ // If we have an outer exception target (i.e. a containing try-finally or try-catch-finally), add a
+ // control flow that goes back through the finally blok and back through each possible exception source.
+ if b.currentExceptionTarget != nil && exceptionLabel.antecedent != nil {
+ b.addAntecedent(b.currentExceptionTarget, b.createReduceLabel(finallyLabel, exceptionLabel.antecedents, b.currentFlow))
+ }
+ // If the end of the finally block is reachable, but the end of the try and catch blocks are not,
+ // convert the current flow to unreachable. For example, 'try { return 1; } finally { ... }' should
+ // result in an unreachable current control flow.
+ if normalExitLabel.antecedent != nil {
+ b.currentFlow = b.createReduceLabel(finallyLabel, normalExitLabel.antecedents, b.currentFlow)
+ } else {
+ b.currentFlow = unreachableFlow
+ }
+ }
+ } else {
+ b.currentFlow = finishFlowLabel(normalExitLabel)
+ }
+}
+
+func (b *Binder) bindSwitchStatement(node *Node) {
+ stmt := node.AsSwitchStatement()
+ postSwitchLabel := b.createBranchLabel()
+ b.bind(stmt.expression)
+ saveBreakTarget := b.currentBreakTarget
+ savePreSwitchCaseFlow := b.preSwitchCaseFlow
+ b.currentBreakTarget = postSwitchLabel
+ b.preSwitchCaseFlow = b.currentFlow
+ b.bind(stmt.caseBlock)
+ b.addAntecedent(postSwitchLabel, b.currentFlow)
+ hasDefault := some(stmt.caseBlock.AsCaseBlock().clauses, func(c *Node) bool {
+ return c.kind == SyntaxKindDefaultClause
+ })
+ if !hasDefault {
+ b.addAntecedent(postSwitchLabel, b.createFlowSwitchClause(b.preSwitchCaseFlow, stmt, 0, 0))
+ }
+ b.currentBreakTarget = saveBreakTarget
+ b.preSwitchCaseFlow = savePreSwitchCaseFlow
+ b.currentFlow = finishFlowLabel(postSwitchLabel)
+}
+
+func (b *Binder) bindCaseBlock(node *Node) {
+ switchStatement := node.parent.AsSwitchStatement()
+ clauses := node.AsCaseBlock().clauses
+ isNarrowingSwitch := switchStatement.expression.kind == SyntaxKindTrueKeyword || isNarrowingExpression(switchStatement.expression)
+ var fallthroughFlow *FlowNode = unreachableFlow
+ for i := 0; i < len(clauses); i++ {
+ clauseStart := i
+ for len(clauses[i].AsCaseOrDefaultClause().statements) == 0 && i+1 < len(clauses) {
+ if fallthroughFlow == unreachableFlow {
+ b.currentFlow = b.preSwitchCaseFlow
+ }
+ b.bind(clauses[i])
+ i++
+ }
+ preCaseLabel := b.createBranchLabel()
+ preCaseFlow := b.preSwitchCaseFlow
+ if isNarrowingSwitch {
+ preCaseFlow = b.createFlowSwitchClause(b.preSwitchCaseFlow, switchStatement, int32(clauseStart), int32(i+1))
+ }
+ b.addAntecedent(preCaseLabel, preCaseFlow)
+ b.addAntecedent(preCaseLabel, fallthroughFlow)
+ b.currentFlow = finishFlowLabel(preCaseLabel)
+ clause := clauses[i]
+ b.bind(clause)
+ fallthroughFlow = b.currentFlow
+ if b.currentFlow.flags&FlowFlagsUnreachable == 0 && i != len(clauses)-1 && b.options.NoFallthroughCasesInSwitch == TSTrue {
+ clause.AsCaseOrDefaultClause().fallthroughFlowNode = b.currentFlow
+ }
+ }
+}
+
+func (b *Binder) bindCaseOrDefaultClause(node *Node) {
+ clause := node.AsCaseOrDefaultClause()
+ if clause.expression != nil {
+ saveCurrentFlow := b.currentFlow
+ b.currentFlow = b.preSwitchCaseFlow
+ b.bind(clause.expression)
+ b.currentFlow = saveCurrentFlow
+ }
+ b.bindEachStatement(clause.statements)
+}
+
+func (b *Binder) bindExpressionStatement(node *Node) {
+ stmt := node.AsExpressionStatement()
+ b.bind(stmt.expression)
+ b.maybeBindExpressionFlowIfCall(stmt.expression)
+}
+
+func (b *Binder) maybeBindExpressionFlowIfCall(node *Node) {
+ // A top level or comma expression call expression with a dotted function name and at least one argument
+ // is potentially an assertion and is therefore included in the control flow.
+ if isCallExpression(node) {
+ expr := node.AsCallExpression()
+ if expr.expression.kind != SyntaxKindSuperKeyword && isDottedName(expr.expression) {
+ b.currentFlow = b.createFlowCall(b.currentFlow, expr)
+ }
+ }
+}
+
+func (b *Binder) bindLabeledStatement(node *Node) {
+ stmt := node.AsLabeledStatement()
+ postStatementLabel := b.createBranchLabel()
+ b.activeLabelList = &ActiveLabel{
+ next: b.activeLabelList,
+ name: stmt.label.AsIdentifier().text,
+ breakTarget: postStatementLabel,
+ continueTarget: nil,
+ referenced: false,
+ }
+ b.bind(stmt.label)
+ b.bind(stmt.statement)
+ if !b.activeLabelList.referenced && b.options.AllowUnusedLabels != TSTrue {
+ b.errorOrSuggestionOnNode(unusedLabelIsError(b.options), stmt.label, diagnostics.Unused_label)
+ }
+ b.activeLabelList = b.activeLabelList.next
+ b.addAntecedent(postStatementLabel, b.currentFlow)
+ b.currentFlow = finishFlowLabel(postStatementLabel)
+}
+
+func (b *Binder) bindPrefixUnaryExpressionFlow(node *Node) {
+ expr := node.AsPrefixUnaryExpression()
+ if expr.operator == SyntaxKindExclamationToken {
+ saveTrueTarget := b.currentTrueTarget
+ b.currentTrueTarget = b.currentFalseTarget
+ b.currentFalseTarget = saveTrueTarget
+ b.bindEachChild(node)
+ b.currentFalseTarget = b.currentTrueTarget
+ b.currentTrueTarget = saveTrueTarget
+ } else {
+ b.bindEachChild(node)
+ if expr.operator == SyntaxKindPlusPlusToken || expr.operator == SyntaxKindMinusMinusToken {
+ b.bindAssignmentTargetFlow(expr.operand)
+ }
+ }
+}
+
+func (b *Binder) bindPostfixUnaryExpressionFlow(node *Node) {
+ expr := node.AsPostfixUnaryExpression()
+ b.bindEachChild(node)
+ if expr.operator == SyntaxKindPlusPlusToken || expr.operator == SyntaxKindMinusMinusToken {
+ b.bindAssignmentTargetFlow(expr.operand)
+ }
+}
+
+func (b *Binder) bindDestructuringAssignmentFlow(node *Node) {
+ expr := node.AsBinaryExpression()
+ if b.inAssignmentPattern {
+ b.inAssignmentPattern = false
+ b.bind(expr.operatorToken)
+ b.bind(expr.right)
+ b.inAssignmentPattern = true
+ b.bind(expr.left)
+ } else {
+ b.inAssignmentPattern = true
+ b.bind(expr.left)
+ b.inAssignmentPattern = false
+ b.bind(expr.operatorToken)
+ b.bind(expr.right)
+ }
+ b.bindAssignmentTargetFlow(expr.left)
+}
+
+func (b *Binder) bindBinaryExpressionFlow(node *Node) {
+ expr := node.AsBinaryExpression()
+ operator := expr.operatorToken.kind
+ if isLogicalOrCoalescingBinaryOperator(operator) || isLogicalOrCoalescingAssignmentOperator(operator) {
+ if isTopLevelLogicalExpression(node) {
+ postExpressionLabel := b.createBranchLabel()
+ saveCurrentFlow := b.currentFlow
+ saveHasFlowEffects := b.hasFlowEffects
+ b.hasFlowEffects = false
+ b.bindLogicalLikeExpression(node, postExpressionLabel, postExpressionLabel)
+ if b.hasFlowEffects {
+ b.currentFlow = finishFlowLabel(postExpressionLabel)
+ } else {
+ b.currentFlow = saveCurrentFlow
+ }
+ b.hasFlowEffects = b.hasFlowEffects || saveHasFlowEffects
+ b.currentFlow = finishFlowLabel(postExpressionLabel)
+ } else {
+ b.bindLogicalLikeExpression(node, b.currentTrueTarget, b.currentFalseTarget)
+ }
+ } else {
+ b.bind(expr.left)
+ if operator == SyntaxKindCommaToken {
+ b.maybeBindExpressionFlowIfCall(node)
+ }
+ b.bind(expr.operatorToken)
+ b.bind(expr.right)
+ if operator == SyntaxKindCommaToken {
+ b.maybeBindExpressionFlowIfCall(node)
+ }
+ if isAssignmentOperator(operator) && !isAssignmentTarget(node) {
+ b.bindAssignmentTargetFlow(expr.left)
+ if operator == SyntaxKindEqualsToken && expr.left.kind == SyntaxKindElementAccessExpression {
+ elementAccess := expr.left.AsElementAccessExpression()
+ if isNarrowableOperand(elementAccess.expression) {
+ b.currentFlow = b.createFlowMutation(FlowFlagsArrayMutation, b.currentFlow, node)
+ }
+ }
+ }
+ }
+}
+
+func (b *Binder) bindLogicalLikeExpression(node *Node, trueTarget *FlowLabel, falseTarget *FlowLabel) {
+ expr := node.AsBinaryExpression()
+ preRightLabel := b.createBranchLabel()
+ if expr.operatorToken.kind == SyntaxKindAmpersandAmpersandToken || expr.operatorToken.kind == SyntaxKindAmpersandAmpersandEqualsToken {
+ b.bindCondition(expr.left, preRightLabel, falseTarget)
+ } else {
+ b.bindCondition(expr.left, trueTarget, preRightLabel)
+ }
+ b.currentFlow = finishFlowLabel(preRightLabel)
+ b.bind(expr.operatorToken)
+ if isLogicalOrCoalescingAssignmentOperator(expr.operatorToken.kind) {
+ b.doWithConditionalBranches(b.bind, expr.right, trueTarget, falseTarget)
+ b.bindAssignmentTargetFlow(expr.left)
+ b.addAntecedent(trueTarget, b.createFlowCondition(FlowFlagsTrueCondition, b.currentFlow, node))
+ b.addAntecedent(falseTarget, b.createFlowCondition(FlowFlagsFalseCondition, b.currentFlow, node))
+ } else {
+ b.bindCondition(expr.right, trueTarget, falseTarget)
+ }
+}
+
+func (b *Binder) bindDeleteExpressionFlow(node *Node) {
+ expr := node.AsDeleteExpression()
+ b.bindEachChild(node)
+ if expr.expression.kind == SyntaxKindPropertyAccessExpression {
+ b.bindAssignmentTargetFlow(expr.expression)
+ }
+}
+
+func (b *Binder) bindConditionalExpressionFlow(node *Node) {
+ expr := node.AsConditionalExpression()
+ trueLabel := b.createBranchLabel()
+ falseLabel := b.createBranchLabel()
+ postExpressionLabel := b.createBranchLabel()
+ saveCurrentFlow := b.currentFlow
+ saveHasFlowEffects := b.hasFlowEffects
+ b.hasFlowEffects = false
+ b.bindCondition(expr.condition, trueLabel, falseLabel)
+ b.currentFlow = finishFlowLabel(trueLabel)
+ b.bind(expr.questionToken)
+ b.bind(expr.whenTrue)
+ b.addAntecedent(postExpressionLabel, b.currentFlow)
+ b.currentFlow = finishFlowLabel(falseLabel)
+ b.bind(expr.colonToken)
+ b.bind(expr.whenFalse)
+ b.addAntecedent(postExpressionLabel, b.currentFlow)
+ if b.hasFlowEffects {
+ b.currentFlow = finishFlowLabel(postExpressionLabel)
+ } else {
+ b.currentFlow = saveCurrentFlow
+ }
+ b.hasFlowEffects = b.hasFlowEffects || saveHasFlowEffects
+}
+
+func (b *Binder) bindVariableDeclarationFlow(node *Node) {
+ b.bindEachChild(node)
+ if node.AsVariableDeclaration().initializer != nil || isForInOrOfStatement(node.parent.parent) {
+ b.bindInitializedVariableFlow(node)
+ }
+}
+
+func (b *Binder) bindInitializedVariableFlow(node *Node) {
+ var name *Node
+ switch node.kind {
+ case SyntaxKindVariableDeclaration:
+ name = node.AsVariableDeclaration().name
+ case SyntaxKindBindingElement:
+ name = node.AsBindingElement().name
+ }
+ if isBindingPattern(name) {
+ for _, child := range name.AsBindingPattern().elements {
+ b.bindInitializedVariableFlow(child)
+ }
+ } else {
+ b.currentFlow = b.createFlowMutation(FlowFlagsAssignment, b.currentFlow, node)
+ }
+}
+
+func (b *Binder) bindAccessExpressionFlow(node *Node) {
+ if isOptionalChain(node) {
+ b.bindOptionalChainFlow(node)
+ } else {
+ b.bindEachChild(node)
+ }
+}
+
+func (b *Binder) bindOptionalChainFlow(node *Node) {
+ if isTopLevelLogicalExpression(node) {
+ postExpressionLabel := b.createBranchLabel()
+ saveCurrentFlow := b.currentFlow
+ saveHasFlowEffects := b.hasFlowEffects
+ b.bindOptionalChain(node, postExpressionLabel, postExpressionLabel)
+ if b.hasFlowEffects {
+ b.currentFlow = finishFlowLabel(postExpressionLabel)
+ } else {
+ b.currentFlow = saveCurrentFlow
+ }
+ b.hasFlowEffects = b.hasFlowEffects || saveHasFlowEffects
+ } else {
+ b.bindOptionalChain(node, b.currentTrueTarget, b.currentFalseTarget)
+ }
+}
+
+func (b *Binder) bindOptionalChain(node *Node, trueTarget *FlowLabel, falseTarget *FlowLabel) {
+ // For an optional chain, we emulate the behavior of a logical expression:
+ //
+ // a?.b -> a && a.b
+ // a?.b.c -> a && a.b.c
+ // a?.b?.c -> a && a.b && a.b.c
+ // a?.[x = 1] -> a && a[x = 1]
+ //
+ // To do this we descend through the chain until we reach the root of a chain (the expression with a `?.`)
+ // and build it's CFA graph as if it were the first condition (`a && ...`). Then we bind the rest
+ // of the node as part of the "true" branch, and continue to do so as we ascend back up to the outermost
+ // chain node. We then treat the entire node as the right side of the expression.
+ var preChainLabel *FlowLabel
+ if isOptionalChainRoot(node) {
+ preChainLabel = b.createBranchLabel()
+ }
+ b.bindOptionalExpression(getAccessedExpression(node), ifElse(preChainLabel != nil, preChainLabel, trueTarget), falseTarget)
+ if preChainLabel != nil {
+ b.currentFlow = finishFlowLabel(preChainLabel)
+ }
+ b.doWithConditionalBranches(b.bindOptionalChainRest, node, trueTarget, falseTarget)
+ if isOutermostOptionalChain(node) {
+ b.addAntecedent(trueTarget, b.createFlowCondition(FlowFlagsTrueCondition, b.currentFlow, node))
+ b.addAntecedent(falseTarget, b.createFlowCondition(FlowFlagsFalseCondition, b.currentFlow, node))
+ }
+}
+
+func (b *Binder) bindOptionalExpression(node *Node, trueTarget *FlowLabel, falseTarget *FlowLabel) {
+ b.doWithConditionalBranches(b.bind, node, trueTarget, falseTarget)
+ if !isOptionalChain(node) || isOutermostOptionalChain(node) {
+ b.addAntecedent(trueTarget, b.createFlowCondition(FlowFlagsTrueCondition, b.currentFlow, node))
+ b.addAntecedent(falseTarget, b.createFlowCondition(FlowFlagsFalseCondition, b.currentFlow, node))
+ }
+}
+
+func (b *Binder) bindOptionalChainRest(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindPropertyAccessExpression:
+ b.bind(node.AsPropertyAccessExpression().questionDotToken)
+ b.bind(node.AsPropertyAccessExpression().name)
+ case SyntaxKindElementAccessExpression:
+ b.bind(node.AsElementAccessExpression().questionDotToken)
+ b.bind(node.AsElementAccessExpression().argumentExpression)
+ case SyntaxKindCallExpression:
+ b.bind(node.AsCallExpression().questionDotToken)
+ b.bind(node.AsCallExpression().typeArguments)
+ b.bindEachExpression(node.AsCallExpression().arguments)
+ }
+ return false
+}
+
+func (b *Binder) bindCallExpressionFlow(node *Node) {
+ call := node.AsCallExpression()
+ if isOptionalChain(node) {
+ b.bindOptionalChainFlow(node)
+ } else {
+ // If the target of the call expression is a function expression or arrow function we have
+ // an immediately invoked function expression (IIFE). Initialize the flowNode property to
+ // the current control flow (which includes evaluation of the IIFE arguments).
+ expr := skipParentheses(call.expression)
+ if expr.kind == SyntaxKindFunctionExpression || expr.kind == SyntaxKindArrowFunction {
+ b.bind(call.typeArguments)
+ b.bindEachExpression(call.arguments)
+ b.bind(call.expression)
+ } else {
+ b.bindEachChild(node)
+ if call.expression.kind == SyntaxKindSuperKeyword {
+ b.currentFlow = b.createFlowCall(b.currentFlow, call)
+ }
+ }
+ }
+ if isPropertyAccessExpression(call.expression) {
+ access := call.expression.AsPropertyAccessExpression()
+ if isIdentifier(access.name) && isNarrowableOperand(access.expression) && isPushOrUnshiftIdentifier(access.name) {
+ b.currentFlow = b.createFlowMutation(FlowFlagsArrayMutation, b.currentFlow, node)
+ }
+ }
+}
+
+func (b *Binder) bindNonNullExpressionFlow(node *Node) {
+ if isOptionalChain(node) {
+ b.bindOptionalChainFlow(node)
+ } else {
+ b.bindEachChild(node)
+ }
+}
+
+func (b *Binder) bindBindingElementFlow(node *Node) {
+ // When evaluating a binding pattern, the initializer is evaluated before the binding pattern, per:
+ // - https://tc39.es/ecma262/#sec-destructuring-binding-patterns-runtime-semantics-iteratorbindinginitialization
+ // - `BindingElement: BindingPattern Initializer?`
+ // - https://tc39.es/ecma262/#sec-runtime-semantics-keyedbindinginitialization
+ // - `BindingElement: BindingPattern Initializer?`
+ elem := node.AsBindingElement()
+ b.bind(elem.dotDotDotToken)
+ b.bind(elem.propertyName)
+ b.bindInitializer(elem.initializer)
+ b.bind(elem.name)
+}
+
+func (b *Binder) bindParameterFlow(node *Node) {
+ param := node.AsParameterDeclaration()
+ b.bind(param.modifiers)
+ b.bind(param.dotDotDotToken)
+ b.bind(param.questionToken)
+ b.bind(param.typeNode)
+ b.bindInitializer(param.initializer)
+ b.bind(param.name)
+}
+
+// a BindingElement/Parameter does not have side effects if initializers are not evaluated and used. (see GH#49759)
+func (b *Binder) bindInitializer(node *Node) {
+ if node == nil {
+ return
+ }
+ entryFlow := b.currentFlow
+ b.bind(node)
+ if entryFlow == unreachableFlow || entryFlow == b.currentFlow {
+ return
+ }
+ exitFlow := b.createBranchLabel()
+ b.addAntecedent(exitFlow, entryFlow)
+ b.addAntecedent(exitFlow, b.currentFlow)
+ b.currentFlow = finishFlowLabel(exitFlow)
+}
+
+func isEnumDeclarationWithPreservedEmit(node *Node, options *CompilerOptions) bool {
+ return node.kind == SyntaxKindEnumDeclaration && (!isEnumConst(node) || shouldPreserveConstEnums(options))
+}
+
+func setFlowNode(node *Node, flowNode *FlowNode) {
+ data := node.FlowNodeData()
+ if data != nil {
+ data.flowNode = flowNode
+ }
+}
+
+func setReturnFlowNode(node *Node, returnFlowNode *FlowNode) {
+ switch node.kind {
+ case SyntaxKindConstructor:
+ node.AsConstructorDeclaration().returnFlowNode = returnFlowNode
+ case SyntaxKindFunctionDeclaration:
+ node.AsFunctionDeclaration().returnFlowNode = returnFlowNode
+ case SyntaxKindFunctionExpression:
+ node.AsFunctionExpression().returnFlowNode = returnFlowNode
+ }
+}
+
+func isGeneratorFunctionExpression(node *Node) bool {
+ return isFunctionExpression(node) && node.AsFunctionExpression().asteriskToken != nil
+}
+
+func (b *Binder) addToContainerChain(next *Node) {
+ if b.lastContainer != nil {
+ next.LocalsContainerData().nextContainer = next
+ }
+ b.lastContainer = next
+}
+
+func (b *Binder) addDeclarationToSymbol(symbol *Symbol, node *Node, symbolFlags SymbolFlags) {
+ symbol.flags |= symbolFlags
+ node.DeclarationData().symbol = symbol
+ if symbol.declarations == nil {
+ symbol.declarations = b.newSingleDeclaration(node)
+ } else {
+ symbol.declarations = appendIfUnique(symbol.declarations, node)
+ }
+ // On merge of const enum module with class or function, reset const enum only flag (namespaces will already recalculate)
+ if symbol.constEnumOnlyModule && symbol.flags&(SymbolFlagsFunction|SymbolFlagsClass|SymbolFlagsRegularEnum) != 0 {
+ symbol.constEnumOnlyModule = false
+ }
+ if symbolFlags&SymbolFlagsValue != 0 {
+ setValueDeclaration(symbol, node)
+ }
+}
+
+func setValueDeclaration(symbol *Symbol, node *Node) {
+ valueDeclaration := symbol.valueDeclaration
+ if valueDeclaration == nil ||
+ !(node.flags&NodeFlagsAmbient != 0 && valueDeclaration.flags&NodeFlagsAmbient == 0) &&
+ (isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) ||
+ (valueDeclaration.kind != node.kind && isEffectiveModuleDeclaration(valueDeclaration)) {
+ // other kinds of value declarations take precedence over modules and assignment declarations
+ symbol.valueDeclaration = node
+ }
+}
+
+/**
+ * Declares a Symbol for the node and adds it to symbols. Reports errors for conflicting identifier names.
+ * @param symbolTable - The symbol table which node will be added to.
+ * @param parent - node's parent declaration.
+ * @param node - The declaration to be added to the symbol table
+ * @param includes - The SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.)
+ * @param excludes - The flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations.
+ */
+
+func getContainerFlags(node *Node) ContainerFlags {
+ switch node.kind {
+ case SyntaxKindClassExpression, SyntaxKindClassDeclaration, SyntaxKindEnumDeclaration, SyntaxKindObjectLiteralExpression, SyntaxKindTypeLiteral,
+ SyntaxKindJSDocTypeLiteral, SyntaxKindJsxAttributes:
+ return ContainerFlagsIsContainer
+ case SyntaxKindInterfaceDeclaration:
+ return ContainerFlagsIsContainer | ContainerFlagsIsInterface
+ case SyntaxKindModuleDeclaration, SyntaxKindTypeAliasDeclaration, SyntaxKindMappedType, SyntaxKindIndexSignature:
+ return ContainerFlagsIsContainer | ContainerFlagsHasLocals
+ case SyntaxKindSourceFile:
+ return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals
+ case SyntaxKindGetAccessor, SyntaxKindSetAccessor, SyntaxKindMethodDeclaration:
+ if isObjectLiteralOrClassExpressionMethodOrAccessor(node) {
+ return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsObjectLiteralOrClassExpressionMethodOrAccessor
+ }
+ fallthrough
+ case SyntaxKindConstructor, SyntaxKindFunctionDeclaration, SyntaxKindMethodSignature, SyntaxKindCallSignature, SyntaxKindJSDocSignature,
+ SyntaxKindJSDocFunctionType, SyntaxKindFunctionType, SyntaxKindConstructSignature, SyntaxKindConstructorType, SyntaxKindClassStaticBlockDeclaration:
+ return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike
+ case SyntaxKindFunctionExpression, SyntaxKindArrowFunction:
+ return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsFunctionExpression
+ case SyntaxKindModuleBlock:
+ return ContainerFlagsIsControlFlowContainer
+ case SyntaxKindPropertyDeclaration:
+ if node.AsPropertyDeclaration().initializer != nil {
+ return ContainerFlagsIsControlFlowContainer
+ } else {
+ return ContainerFlagsNone
+ }
+ case SyntaxKindCatchClause, SyntaxKindForStatement, SyntaxKindForInStatement, SyntaxKindForOfStatement, SyntaxKindCaseBlock:
+ return ContainerFlagsIsBlockScopedContainer | ContainerFlagsHasLocals
+ case SyntaxKindBlock:
+ if isFunctionLike(node.parent) || isClassStaticBlockDeclaration(node.parent) {
+ return ContainerFlagsNone
+ } else {
+ return ContainerFlagsIsBlockScopedContainer | ContainerFlagsHasLocals
+ }
+ }
+ return ContainerFlagsNone
+}
+
+func isNarrowingExpression(expr *Node) bool {
+ switch expr.kind {
+ case SyntaxKindIdentifier, SyntaxKindThisKeyword:
+ return true
+ case SyntaxKindPropertyAccessExpression, SyntaxKindElementAccessExpression:
+ return containsNarrowableReference(expr)
+ case SyntaxKindCallExpression:
+ return hasNarrowableArgument(expr)
+ case SyntaxKindParenthesizedExpression:
+ // if isJSDocTypeAssertion(expr) {
+ // return false
+ // }
+ return isNarrowingExpression(expr.AsParenthesizedExpression().expression)
+ case SyntaxKindNonNullExpression:
+ return isNarrowingExpression(expr.AsNonNullExpression().expression)
+ case SyntaxKindBinaryExpression:
+ return isNarrowingBinaryExpression(expr.AsBinaryExpression())
+ case SyntaxKindPrefixUnaryExpression:
+ return expr.AsPrefixUnaryExpression().operator == SyntaxKindExclamationToken && isNarrowingExpression(expr.AsPrefixUnaryExpression().operand)
+ case SyntaxKindTypeOfExpression:
+ return isNarrowingExpression(expr.AsTypeOfExpression().expression)
+ }
+ return false
+}
+
+func containsNarrowableReference(expr *Node) bool {
+ if isNarrowableReference(expr) {
+ return true
+ }
+ if expr.flags&NodeFlagsOptionalChain != 0 {
+ switch expr.kind {
+ case SyntaxKindPropertyAccessExpression:
+ return containsNarrowableReference(expr.AsPropertyAccessExpression().expression)
+ case SyntaxKindElementAccessExpression:
+ return containsNarrowableReference(expr.AsElementAccessExpression().expression)
+ case SyntaxKindCallExpression:
+ return containsNarrowableReference(expr.AsCallExpression().expression)
+ case SyntaxKindNonNullExpression:
+ return containsNarrowableReference(expr.AsNonNullExpression().expression)
+ }
+ }
+ return false
+}
+
+func isNarrowableReference(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindIdentifier, SyntaxKindThisKeyword, SyntaxKindSuperKeyword, SyntaxKindMetaProperty:
+ return true
+ case SyntaxKindPropertyAccessExpression:
+ return isNarrowableReference(node.AsPropertyAccessExpression().expression)
+ case SyntaxKindParenthesizedExpression:
+ return isNarrowableReference(node.AsParenthesizedExpression().expression)
+ case SyntaxKindNonNullExpression:
+ return isNarrowableReference(node.AsNonNullExpression().expression)
+ case SyntaxKindElementAccessExpression:
+ expr := node.AsElementAccessExpression()
+ return isStringOrNumericLiteralLike(expr.argumentExpression) ||
+ isEntityNameExpression(expr.argumentExpression) && isNarrowableReference(expr.expression)
+ case SyntaxKindBinaryExpression:
+ expr := node.AsBinaryExpression()
+ return expr.operatorToken.kind == SyntaxKindCommaToken && isNarrowableReference(expr.right) ||
+ isAssignmentOperator(expr.operatorToken.kind) && isLeftHandSideExpression(expr.left)
+ }
+ return false
+}
+
+func hasNarrowableArgument(expr *Node) bool {
+ call := expr.AsCallExpression()
+ for _, argument := range call.arguments {
+ if containsNarrowableReference(argument) {
+ return true
+ }
+ }
+ if isPropertyAccessExpression(call.expression) {
+ if containsNarrowableReference(call.expression.AsPropertyAccessExpression().expression) {
+ return true
+ }
+ }
+ return false
+}
+
+func isNarrowingBinaryExpression(expr *BinaryExpression) bool {
+ switch expr.operatorToken.kind {
+ case SyntaxKindEqualsToken, SyntaxKindBarBarEqualsToken, SyntaxKindAmpersandAmpersandEqualsToken, SyntaxKindQuestionQuestionEqualsToken:
+ return containsNarrowableReference(expr.left)
+ case SyntaxKindEqualsEqualsToken, SyntaxKindExclamationEqualsToken, SyntaxKindEqualsEqualsEqualsToken, SyntaxKindExclamationEqualsEqualsToken:
+ return isNarrowableOperand(expr.left) || isNarrowableOperand(expr.right) ||
+ isNarrowingTypeOfOperands(expr.right, expr.left) || isNarrowingTypeOfOperands(expr.left, expr.right) ||
+ (isBooleanLiteral(expr.right) && isNarrowingExpression(expr.left) || isBooleanLiteral(expr.left) && isNarrowingExpression(expr.right))
+ case SyntaxKindInstanceOfKeyword:
+ return isNarrowableOperand(expr.left)
+ case SyntaxKindInKeyword:
+ return isNarrowingExpression(expr.right)
+ case SyntaxKindCommaToken:
+ return isNarrowingExpression(expr.right)
+ }
+ return false
+}
+
+func isNarrowableOperand(expr *Node) bool {
+ switch expr.kind {
+ case SyntaxKindParenthesizedExpression:
+ return isNarrowableOperand(expr.AsParenthesizedExpression().expression)
+ case SyntaxKindBinaryExpression:
+ binary := expr.AsBinaryExpression()
+ switch binary.operatorToken.kind {
+ case SyntaxKindEqualsToken:
+ return isNarrowableOperand(binary.left)
+ case SyntaxKindCommaToken:
+ return isNarrowableOperand(binary.right)
+ }
+ }
+ return containsNarrowableReference(expr)
+}
+
+func isNarrowingTypeOfOperands(expr1 *Node, expr2 *Node) bool {
+ return isTypeOfExpression(expr1) && isNarrowableOperand(expr1.AsTypeOfExpression().expression) && isStringLiteralLike(expr2)
+}
+
+func (b *Binder) errorOnNode(node *Node, message *diagnostics.Message, args ...any) {
+ b.addDiagnostic(b.createDiagnosticForNode(node, message, args...))
+}
+
+func (b *Binder) errorOnFirstToken(node *Node, message *diagnostics.Message, args ...any) {
+ span := getRangeOfTokenAtPosition(b.file, node.Pos())
+ b.addDiagnostic(NewDiagnostic(b.file, span, message, args...))
+}
+
+func (b *Binder) errorOrSuggestionOnNode(isError bool, node *Node, message *diagnostics.Message) {
+ b.errorOrSuggestionOnRange(isError, node, node, message)
+}
+
+func (b *Binder) errorOrSuggestionOnRange(isError bool, startNode *Node, endNode *Node, message *diagnostics.Message) {
+ textRange := NewTextRange(getRangeOfTokenAtPosition(b.file, startNode.Pos()).Pos(), endNode.End())
+ diagnostic := NewDiagnostic(b.file, textRange, message)
+ if isError {
+ b.addDiagnostic(diagnostic)
+ } else {
+ diagnostic.SetCategory(diagnostics.CategorySuggestion)
+ b.file.bindSuggestionDiagnostics = append(b.file.bindSuggestionDiagnostics, diagnostic)
+ }
+}
+
+// Inside the binder, we may create a diagnostic for an as-yet unbound node (with potentially no parent pointers, implying no accessible source file)
+// If so, the node _must_ be in the current file (as that's the only way anything could have traversed to it to yield it as the error node)
+// This version of `createDiagnosticForNode` uses the binder's context to account for this, and always yields correct diagnostics even in these situations.
+func (b *Binder) createDiagnosticForNode(node *Node, message *diagnostics.Message, args ...any) *Diagnostic {
+ return NewDiagnostic(b.file, getErrorRangeForNode(b.file, node), message, args...)
+}
+
+func (b *Binder) addDiagnostic(diagnostic *Diagnostic) {
+ b.file.bindDiagnostics = append(b.file.bindDiagnostics, diagnostic)
+}
+
+func isEnumConst(node *Node) bool {
+ return getCombinedModifierFlags(node)&ModifierFlagsConst != 0
+}
diff --git a/internal/compiler/checker.go b/internal/compiler/checker.go
new file mode 100644
index 0000000000..f4e63af5fa
--- /dev/null
+++ b/internal/compiler/checker.go
@@ -0,0 +1,5064 @@
+package compiler
+
+import (
+ "fmt"
+ "maps"
+ "slices"
+ "strconv"
+ "strings"
+
+ "github.com/microsoft/typescript-go/internal/compiler/diagnostics"
+)
+
+// CheckMode
+
+type CheckMode uint32
+
+const (
+ CheckModeNormal CheckMode = 0 // Normal type checking
+ CheckModeContextual CheckMode = 1 << 0 // Explicitly assigned contextual type, therefore not cacheable
+ CheckModeInferential CheckMode = 1 << 1 // Inferential typing
+ CheckModeSkipContextSensitive CheckMode = 1 << 2 // Skip context sensitive function expressions
+ CheckModeSkipGenericFunctions CheckMode = 1 << 3 // Skip single signature generic functions
+ CheckModeIsForSignatureHelp CheckMode = 1 << 4 // Call resolution for purposes of signature help
+ CheckModeRestBindingElement CheckMode = 1 << 5 // Checking a type that is going to be used to determine the type of a rest binding element
+ // e.g. in `const { a, ...rest } = foo`, when checking the type of `foo` to determine the type of `rest`,
+ // we need to preserve generic types instead of substituting them for constraints
+ CheckModeTypeOnly CheckMode = 1 << 6 // Called from getTypeOfExpression, diagnostics may be omitted
+)
+
+type TypeSystemEntity any
+
+type TypeSystemPropertyName int32
+
+const (
+ TypeSystemPropertyNameType TypeSystemPropertyName = iota
+ TypeSystemPropertyNameResolvedBaseConstructorType
+ TypeSystemPropertyNameDeclaredType
+ TypeSystemPropertyNameResolvedReturnType
+ TypeSystemPropertyNameImmediateBaseConstraint
+ TypeSystemPropertyNameResolvedTypeArguments
+ TypeSystemPropertyNameResolvedBaseTypes
+ TypeSystemPropertyNameWriteType
+ TypeSystemPropertyNameParameterInitializerContainsUndefined
+)
+
+type TypeResolution struct {
+ target TypeSystemEntity
+ propertyName TypeSystemPropertyName
+ result bool
+}
+
+// WideningKind
+
+type WideningKind int32
+
+const (
+ WideningKindNormal WideningKind = iota
+ WideningKindFunctionReturn
+ WideningKindGeneratorNext
+ WideningKindGeneratorYield
+)
+
+// EnumLiteralKey
+
+type EnumLiteralKey struct {
+ enumSymbol *Symbol
+ value any
+}
+
+// TypeCacheKind
+
+type CachedTypeKind int32
+
+const (
+ CachedTypeKindLiteralUnionBaseType CachedTypeKind = iota
+)
+
+// TypeCacheKey
+
+type CachedTypeKey struct {
+ kind CachedTypeKind
+ typeId TypeId
+}
+
+// UnionOfUnionKey
+
+type UnionOfUnionKey struct {
+ id1 TypeId
+ id2 TypeId
+ r UnionReduction
+ a string
+}
+
+// InferenceContext
+
+type InferenceContext struct{}
+
+// Checker
+
+type Checker struct {
+ program *Program
+ host CompilerHost
+ compilerOptions *CompilerOptions
+ files []*SourceFile
+ typeCount uint32
+ symbolCount uint32
+ instantiationCount uint32
+ currentNode *Node
+ emptySymbols SymbolTable
+ languageVersion ScriptTarget
+ moduleKind ModuleKind
+ allowSyntheticDefaultImports bool
+ strictNullChecks bool
+ noImplicitAny bool
+ useUnknownInCatchVariables bool
+ exactOptionalPropertyTypes bool
+ globals SymbolTable
+ stringLiteralTypes map[string]*Type
+ numberLiteralTypes map[float64]*Type
+ bigintLiteralTypes map[PseudoBigint]*Type
+ enumLiteralTypes map[EnumLiteralKey]*Type
+ cachedTypes map[CachedTypeKey]*Type
+ undefinedSymbol *Symbol
+ argumentsSymbol *Symbol
+ requireSymbol *Symbol
+ unknownSymbol *Symbol
+ resolvingSymbol *Symbol
+ globalThisSymbol *Symbol
+ resolveName func(location *Node, name string, meaning SymbolFlags, nameNotFoundMessage *diagnostics.Message, isUse bool, excludeGlobals bool) *Symbol
+ unionTypes map[string]*Type
+ unionOfUnionTypes map[UnionOfUnionKey]*Type
+ diagnostics DiagnosticsCollection
+ suggestionDiagnostics DiagnosticsCollection
+ symbolPool Pool[Symbol]
+ mergedSymbols map[MergeId]*Symbol
+ nodeLinks LinkStore[*Node, NodeLinks]
+ valueSymbolLinks LinkStore[*Symbol, ValueSymbolLinks]
+ aliasSymbolLinks LinkStore[*Symbol, AliasSymbolLinks]
+ moduleSymbolLinks LinkStore[*Symbol, ModuleSymbolLinks]
+ exportTypeLinks LinkStore[*Symbol, ExportTypeLinks]
+ membersAndExportsLinks LinkStore[*Symbol, MembersAndExportsLinks]
+ typeParameterLinks LinkStore[*Symbol, TypeParameterLinks]
+ interfaceTypeLinks LinkStore[*Symbol, InterfaceTypeLinks]
+ anyType *Type
+ autoType *Type
+ wildcardType *Type
+ errorType *Type
+ nonInferrableAnyType *Type
+ intrinsicMarkerType *Type
+ unknownType *Type
+ undefinedType *Type
+ undefinedWideningType *Type
+ missingType *Type
+ undefinedOrMissingType *Type
+ nullType *Type
+ nullWideningType *Type
+ stringType *Type
+ numberType *Type
+ bigintType *Type
+ regularFalseType *Type
+ falseType *Type
+ regularTrueType *Type
+ trueType *Type
+ booleanType *Type
+ esSymbolType *Type
+ voidType *Type
+ neverType *Type
+ nonPrimitiveType *Type
+ emptyObjectType *Type
+ emptyTypeLiteralType *Type
+ anyFunctionType *Type
+ enumNumberIndexInfo *IndexInfo
+ patternAmbientModules []PatternAmbientModule
+ patternAmbientModuleAugmentations SymbolTable
+ globalObjectType *Type
+ globalFunctionType *Type
+ globalCallableFunctionType *Type
+ globalNewableFunctionType *Type
+ anyArrayType *Type
+ autoArrayType *Type
+ anyReadonlyArrayType *Type
+ contextualBindingPatterns []*Node
+ typeResolutions []TypeResolution
+ resolutionStart int
+ lastGetCombinedNodeFlagsNode *Node
+ lastGetCombinedNodeFlagsResult NodeFlags
+ lastGetCombinedModifierFlagsNode *Node
+ lastGetCombinedModifierFlagsResult ModifierFlags
+}
+
+func NewChecker(program *Program) *Checker {
+ c := &Checker{}
+ c.program = program
+ c.host = program.host
+ c.compilerOptions = program.options
+ c.files = program.files
+ c.emptySymbols = make(SymbolTable)
+ c.languageVersion = getEmitScriptTarget(c.compilerOptions)
+ c.moduleKind = getEmitModuleKind(c.compilerOptions)
+ c.allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(c.compilerOptions)
+ c.strictNullChecks = c.getStrictOptionValue(c.compilerOptions.StrictNullChecks)
+ c.noImplicitAny = c.getStrictOptionValue(c.compilerOptions.NoImplicitAny)
+ c.useUnknownInCatchVariables = c.getStrictOptionValue(c.compilerOptions.UseUnknownInCatchVariables)
+ c.exactOptionalPropertyTypes = c.compilerOptions.ExactOptionalPropertyTypes == TSTrue
+ c.globals = make(SymbolTable)
+ c.stringLiteralTypes = make(map[string]*Type)
+ c.numberLiteralTypes = make(map[float64]*Type)
+ c.bigintLiteralTypes = make(map[PseudoBigint]*Type)
+ c.enumLiteralTypes = make(map[EnumLiteralKey]*Type)
+ c.undefinedSymbol = c.newSymbol(SymbolFlagsProperty, "undefined")
+ c.argumentsSymbol = c.newSymbol(SymbolFlagsProperty, "arguments")
+ c.requireSymbol = c.newSymbol(SymbolFlagsProperty, "require")
+ c.unknownSymbol = c.newSymbol(SymbolFlagsProperty, "unknown")
+ c.resolvingSymbol = c.newSymbol(SymbolFlagsNone, InternalSymbolNameResolving)
+ c.globalThisSymbol = c.newSymbolEx(SymbolFlagsModule, "globalThis", CheckFlagsReadonly)
+ c.globalThisSymbol.exports = c.globals
+ c.globals[c.globalThisSymbol.name] = c.globalThisSymbol
+ c.resolveName = c.createNameResolver().resolve
+ c.unionTypes = make(map[string]*Type)
+ c.unionOfUnionTypes = make(map[UnionOfUnionKey]*Type)
+ c.diagnostics = DiagnosticsCollection{}
+ c.suggestionDiagnostics = DiagnosticsCollection{}
+ c.mergedSymbols = make(map[MergeId]*Symbol)
+ c.anyType = c.newIntrinsicType(TypeFlagsAny, "any")
+ c.autoType = c.newIntrinsicTypeEx(TypeFlagsAny, "any", ObjectFlagsNonInferrableType)
+ c.wildcardType = c.newIntrinsicType(TypeFlagsAny, "any")
+ c.errorType = c.newIntrinsicType(TypeFlagsAny, "error")
+ c.nonInferrableAnyType = c.newIntrinsicTypeEx(TypeFlagsAny, "any", ObjectFlagsContainsWideningType)
+ c.intrinsicMarkerType = c.newIntrinsicType(TypeFlagsAny, "intrinsic")
+ c.unknownType = c.newIntrinsicType(TypeFlagsUnknown, "unknown")
+ c.undefinedType = c.newIntrinsicType(TypeFlagsUndefined, "undefined")
+ c.undefinedWideningType = c.createWideningType(c.undefinedType)
+ c.missingType = c.newIntrinsicType(TypeFlagsUndefined, "undefined")
+ c.undefinedOrMissingType = ifElse(c.exactOptionalPropertyTypes, c.missingType, c.undefinedType)
+ c.nullType = c.newIntrinsicType(TypeFlagsNull, "null")
+ c.nullWideningType = c.createWideningType(c.nullType)
+ c.stringType = c.newIntrinsicType(TypeFlagsString, "string")
+ c.numberType = c.newIntrinsicType(TypeFlagsNumber, "number")
+ c.bigintType = c.newIntrinsicType(TypeFlagsBigint, "bigint")
+ c.regularFalseType = c.newLiteralType(TypeFlagsBooleanLiteral, false, nil)
+ c.falseType = c.newLiteralType(TypeFlagsBooleanLiteral, false, c.regularFalseType)
+ c.regularFalseType.LiteralType().freshType = c.falseType
+ c.falseType.LiteralType().freshType = c.falseType
+ c.regularTrueType = c.newLiteralType(TypeFlagsBooleanLiteral, false, nil)
+ c.trueType = c.newLiteralType(TypeFlagsBooleanLiteral, false, c.regularTrueType)
+ c.regularTrueType.LiteralType().freshType = c.trueType
+ c.trueType.LiteralType().freshType = c.trueType
+ c.booleanType = c.getUnionType([]*Type{c.regularFalseType, c.regularTrueType})
+ c.esSymbolType = c.newIntrinsicType(TypeFlagsESSymbol, "symbol")
+ c.voidType = c.newIntrinsicType(TypeFlagsVoid, "void")
+ c.neverType = c.newIntrinsicType(TypeFlagsNever, "never")
+ c.nonPrimitiveType = c.newIntrinsicType(TypeFlagsNonPrimitive, "object")
+ c.emptyObjectType = c.newAnonymousType(nil /*symbol*/, nil, nil, nil, nil)
+ c.emptyTypeLiteralType = c.newAnonymousType(c.newSymbol(SymbolFlagsTypeLiteral, InternalSymbolNameType), nil, nil, nil, nil)
+ c.anyFunctionType = c.newAnonymousType(nil /*symbol*/, nil, nil, nil, nil)
+ c.anyFunctionType.objectFlags |= ObjectFlagsNonInferrableType
+ c.enumNumberIndexInfo = &IndexInfo{keyType: c.numberType, valueType: c.stringType, isReadonly: true}
+ c.globalObjectType = c.emptyObjectType // !!!
+ c.globalFunctionType = c.emptyObjectType // !!!
+ c.globalCallableFunctionType = c.emptyObjectType // !!!
+ c.globalNewableFunctionType = c.emptyObjectType // !!!
+ c.anyArrayType = c.anyType // !!!
+ c.autoArrayType = c.anyType // !!!
+ c.anyReadonlyArrayType = c.anyType // !!!
+ c.initializeChecker()
+ return c
+}
+
+func (c *Checker) getStrictOptionValue(value Tristate) bool {
+ if value != TSUnknown {
+ return value == TSTrue
+ }
+ return c.compilerOptions.Strict == TSTrue
+}
+
+func (c *Checker) initializeChecker() {
+ c.program.bindSourceFiles()
+ // Initialize global symbol table
+ var augmentations [][]*Node
+ for _, file := range c.files {
+ if !isExternalOrCommonJsModule(file) {
+ c.mergeSymbolTable(c.globals, file.locals, false, nil)
+ }
+ c.patternAmbientModules = append(c.patternAmbientModules, file.patternAmbientModules...)
+ augmentations = append(augmentations, file.moduleAugmentations)
+ if file.symbol != nil {
+ // Merge in UMD exports with first-in-wins semantics (see #9771)
+ for name, symbol := range file.symbol.globalExports {
+ if _, ok := c.globals[name]; !ok {
+ c.globals[name] = symbol
+ }
+ }
+ }
+ }
+ // We do global augmentations separately from module augmentations (and before creating global types) because they
+ // 1. Affect global types. We won't have the correct global types until global augmentations are merged. Also,
+ // 2. Module augmentation instantiation requires creating the type of a module, which, in turn, can require
+ // checking for an export or property on the module (if export=) which, in turn, can fall back to the
+ // apparent type of the module - either globalObjectType or globalFunctionType - which wouldn't exist if we
+ // did module augmentations prior to finalizing the global types.
+ for _, list := range augmentations {
+ for _, augmentation := range list {
+ // Merge 'global' module augmentations. This needs to be done after global symbol table is initialized to
+ // make sure that all ambient modules are indexed
+ if isGlobalScopeAugmentation(augmentation.parent) {
+ c.mergeModuleAugmentation(augmentation)
+ }
+ }
+ }
+ c.addUndefinedToGlobalsOrErrorOnRedeclaration()
+ c.valueSymbolLinks.get(c.undefinedSymbol).resolvedType = c.undefinedWideningType
+ c.valueSymbolLinks.get(c.argumentsSymbol).resolvedType = c.errorType // !!!
+ c.valueSymbolLinks.get(c.unknownSymbol).resolvedType = c.errorType
+ c.valueSymbolLinks.get(c.globalThisSymbol).resolvedType = c.newObjectType(ObjectFlagsAnonymous, c.globalThisSymbol)
+
+ // merge _nonglobal_ module augmentations.
+ // this needs to be done after global symbol table is initialized to make sure that all ambient modules are indexed
+ for _, list := range augmentations {
+ for _, augmentation := range list {
+ if !isGlobalScopeAugmentation(augmentation.parent) {
+ c.mergeModuleAugmentation(augmentation)
+ }
+ }
+ }
+}
+
+func (c *Checker) mergeModuleAugmentation(moduleName *Node) {
+ moduleNode := moduleName.parent
+ moduleAugmentation := moduleNode.AsModuleDeclaration()
+ if moduleAugmentation.symbol.declarations[0] != moduleNode {
+ // this is a combined symbol for multiple augmentations within the same file.
+ // its symbol already has accumulated information for all declarations
+ // so we need to add it just once - do the work only for first declaration
+ return
+ }
+ if isGlobalScopeAugmentation(moduleNode) {
+ c.mergeSymbolTable(c.globals, moduleAugmentation.symbol.exports, false /*unidirectional*/, nil /*parent*/)
+ } else {
+ // find a module that about to be augmented
+ // do not validate names of augmentations that are defined in ambient context
+ var moduleNotFoundError *diagnostics.Message
+ if moduleName.parent.parent.flags&NodeFlagsAmbient == 0 {
+ moduleNotFoundError = diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found
+ }
+ mainModule := c.resolveExternalModuleNameWorker(moduleName, moduleName, moduleNotFoundError /*ignoreErrors*/, false /*isForAugmentation*/, true)
+ if mainModule == nil {
+ return
+ }
+ // obtain item referenced by 'export='
+ mainModule = c.resolveExternalModuleSymbol(mainModule, false /*dontResolveAlias*/)
+ if mainModule.flags&SymbolFlagsNamespace != 0 {
+ // If we're merging an augmentation to a pattern ambient module, we want to
+ // perform the merge unidirectionally from the augmentation ('a.foo') to
+ // the pattern ('*.foo'), so that 'getMergedSymbol()' on a.foo gives you
+ // all the exports both from the pattern and from the augmentation, but
+ // 'getMergedSymbol()' on *.foo only gives you exports from *.foo.
+ if some(c.patternAmbientModules, func(module PatternAmbientModule) bool {
+ return mainModule == module.symbol
+ }) {
+ merged := c.mergeSymbol(moduleAugmentation.symbol, mainModule, true /*unidirectional*/)
+ if c.patternAmbientModuleAugmentations == nil {
+ c.patternAmbientModuleAugmentations = make(SymbolTable)
+ }
+ // moduleName will be a StringLiteral since this is not `declare global`.
+ c.patternAmbientModuleAugmentations[getTextOfIdentifierOrLiteral(moduleName)] = merged
+ } else {
+ if mainModule.exports[InternalSymbolNameExportStar] != nil && len(moduleAugmentation.symbol.exports) != 0 {
+ // We may need to merge the module augmentation's exports into the target symbols of the resolved exports
+ resolvedExports := c.getResolvedMembersOrExportsOfSymbol(mainModule, MembersOrExportsResolutionKindResolvedExports)
+ for key, value := range moduleAugmentation.symbol.exports {
+ if resolvedExports[key] != nil && mainModule.exports[key] == nil {
+ c.mergeSymbol(resolvedExports[key], value, false /*unidirectional*/)
+ }
+ }
+ }
+ c.mergeSymbol(mainModule, moduleAugmentation.symbol, false /*unidirectional*/)
+ }
+ } else {
+ // moduleName will be a StringLiteral since this is not `declare global`.
+ c.error(moduleName, diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, getTextOfIdentifierOrLiteral(moduleName))
+ }
+ }
+}
+
+func (c *Checker) addUndefinedToGlobalsOrErrorOnRedeclaration() {
+ name := c.undefinedSymbol.name
+ targetSymbol := c.globals[name]
+ if targetSymbol != nil {
+ for _, declaration := range targetSymbol.declarations {
+ if !isTypeDeclaration(declaration) {
+ c.diagnostics.add(createDiagnosticForNode(declaration, diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, name))
+ }
+ }
+ } else {
+ c.globals[name] = c.undefinedSymbol
+ }
+}
+
+func (c *Checker) createNameResolver() *NameResolver {
+ return &NameResolver{
+ compilerOptions: c.compilerOptions,
+ getSymbolOfDeclaration: c.getSymbolOfDeclaration,
+ error: c.error,
+ globals: c.globals,
+ argumentsSymbol: c.argumentsSymbol,
+ requireSymbol: c.requireSymbol,
+ lookup: c.getSymbol,
+ setRequiresScopeChangeCache: c.setRequiresScopeChangeCache,
+ getRequiresScopeChangeCache: c.getRequiresScopeChangeCache,
+ onPropertyWithInvalidInitializer: c.checkAndReportErrorForInvalidInitializer,
+ onFailedToResolveSymbol: c.onFailedToResolveSymbol,
+ onSuccessfullyResolvedSymbol: c.onSuccessfullyResolvedSymbol,
+ }
+}
+
+func (c *Checker) getRequiresScopeChangeCache(node *Node) Tristate {
+ return c.nodeLinks.get(node).declarationRequiresScopeChange
+}
+
+func (c *Checker) setRequiresScopeChangeCache(node *Node, value Tristate) {
+ c.nodeLinks.get(node).declarationRequiresScopeChange = value
+}
+
+// The invalid initializer error is needed in two situation:
+// 1. When result is undefined, after checking for a missing "this."
+// 2. When result is defined
+func (c *Checker) checkAndReportErrorForInvalidInitializer(errorLocation *Node, name string, propertyWithInvalidInitializer *Node, result *Symbol) bool {
+ if !getEmitStandardClassFields(c.compilerOptions) {
+ if errorLocation != nil && result == nil && c.checkAndReportErrorForMissingPrefix(errorLocation, name) {
+ return true
+ }
+ // We have a match, but the reference occurred within a property initializer and the identifier also binds
+ // to a local variable in the constructor where the code will be emitted. Note that this is actually allowed
+ // with emitStandardClassFields because the scope semantics are different.
+ prop := propertyWithInvalidInitializer.AsPropertyDeclaration()
+ message := ifElse(errorLocation != nil && prop.typeNode != nil && prop.typeNode.loc.ContainsInclusive(errorLocation.Pos()),
+ diagnostics.Type_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor,
+ diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor)
+ c.error(errorLocation, message, declarationNameToString(prop.name), name)
+ return true
+ }
+ return false
+}
+
+func (c *Checker) onFailedToResolveSymbol(errorLocation *Node, name string, meaning SymbolFlags, nameNotFoundMessage *diagnostics.Message) {
+ // !!!
+ c.error(errorLocation, nameNotFoundMessage, name, "???")
+}
+
+func (c *Checker) onSuccessfullyResolvedSymbol(errorLocation *Node, result *Symbol, meaning SymbolFlags, lastLocation *Node, associatedDeclarationForContainingInitializerOrBindingName *Node, withinDeferredContext bool) {
+ name := result.name
+ isInExternalModule := lastLocation != nil && isSourceFile(lastLocation) && isExternalOrCommonJsModule(lastLocation.AsSourceFile())
+ // Only check for block-scoped variable if we have an error location and are looking for the
+ // name with variable meaning
+ // For example,
+ // declare module foo {
+ // interface bar {}
+ // }
+ // const foo/*1*/: foo/*2*/.bar;
+ // The foo at /*1*/ and /*2*/ will share same symbol with two meanings:
+ // block-scoped variable and namespace module. However, only when we
+ // try to resolve name in /*1*/ which is used in variable position,
+ // we want to check for block-scoped
+ if errorLocation != nil && (meaning&SymbolFlagsBlockScopedVariable != 0 || meaning&(SymbolFlagsClass|SymbolFlagsEnum) != 0 && meaning&SymbolFlagsValue == SymbolFlagsValue) {
+ exportOrLocalSymbol := c.getExportSymbolOfValueSymbolIfExported(result)
+ if exportOrLocalSymbol.flags&(SymbolFlagsBlockScopedVariable|SymbolFlagsClass|SymbolFlagsEnum) != 0 {
+ c.checkResolvedBlockScopedVariable(exportOrLocalSymbol, errorLocation)
+ }
+ }
+ // If we're in an external module, we can't reference value symbols created from UMD export declarations
+ if isInExternalModule && (meaning&SymbolFlagsValue) == SymbolFlagsValue && errorLocation.flags&NodeFlagsJSDoc == 0 {
+ merged := c.getMergedSymbol(result)
+ if len(merged.declarations) != 0 && every(merged.declarations, func(d *Node) bool {
+ return isNamespaceExportDeclaration(d) || isSourceFile(d) && d.Symbol().globalExports != nil
+ }) {
+ c.errorOrSuggestion(c.compilerOptions.AllowUmdGlobalAccess != TSTrue, errorLocation, diagnostics.X_0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead, name)
+ }
+ }
+ // If we're in a parameter initializer or binding name, we can't reference the values of the parameter whose initializer we're within or parameters to the right
+ if associatedDeclarationForContainingInitializerOrBindingName != nil && !withinDeferredContext && (meaning&SymbolFlagsValue) == SymbolFlagsValue {
+ candidate := c.getMergedSymbol(c.getLateBoundSymbol(result))
+ root := getRootDeclaration(associatedDeclarationForContainingInitializerOrBindingName)
+ // A parameter initializer or binding pattern initializer within a parameter cannot refer to itself
+ if candidate == c.getSymbolOfDeclaration(associatedDeclarationForContainingInitializerOrBindingName) {
+ c.error(errorLocation, diagnostics.Parameter_0_cannot_reference_itself, declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.Name()))
+ } else if candidate.valueDeclaration != nil && candidate.valueDeclaration.Pos() > associatedDeclarationForContainingInitializerOrBindingName.Pos() && root.parent.LocalsContainerData().locals != nil && c.getSymbol(root.parent.LocalsContainerData().locals, candidate.name, meaning) == candidate {
+ c.error(errorLocation, diagnostics.Parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.Name()), declarationNameToString(errorLocation))
+ }
+ }
+ if errorLocation != nil && meaning&SymbolFlagsValue != 0 && result.flags&SymbolFlagsAlias != 0 && result.flags&SymbolFlagsValue == 0 && !isValidTypeOnlyAliasUseSite(errorLocation) {
+ typeOnlyDeclaration := c.getTypeOnlyAliasDeclarationEx(result, SymbolFlagsValue)
+ if typeOnlyDeclaration != nil {
+ message := ifElse(nodeKindIs(typeOnlyDeclaration, SyntaxKindExportSpecifier, SyntaxKindExportDeclaration, SyntaxKindNamespaceExport),
+ diagnostics.X_0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type,
+ diagnostics.X_0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type)
+ c.addTypeOnlyDeclarationRelatedInfo(c.error(errorLocation, message, name), typeOnlyDeclaration, name)
+ }
+ }
+ // Look at 'compilerOptions.isolatedModules' and not 'getIsolatedModules(...)' (which considers 'verbatimModuleSyntax')
+ // here because 'verbatimModuleSyntax' will already have an error for importing a type without 'import type'.
+ if c.compilerOptions.IsolatedModules == TSTrue && result != nil && isInExternalModule && (meaning&SymbolFlagsValue) == SymbolFlagsValue {
+ isGlobal := c.getSymbol(c.globals, name, meaning) == result
+ var nonValueSymbol *Symbol
+ if isGlobal && isSourceFile(lastLocation) {
+ nonValueSymbol = c.getSymbol(lastLocation.AsSourceFile().locals, name, ^SymbolFlagsValue)
+ }
+ if nonValueSymbol != nil {
+ importDecl := find(nonValueSymbol.declarations, func(d *Node) bool {
+ return nodeKindIs(d, SyntaxKindImportSpecifier, SyntaxKindImportClause, SyntaxKindNamespaceImport, SyntaxKindImportEqualsDeclaration)
+ })
+ if importDecl != nil && !isTypeOnlyImportDeclaration(importDecl) {
+ c.error(importDecl, diagnostics.Import_0_conflicts_with_global_value_used_in_this_file_so_must_be_declared_with_a_type_only_import_when_isolatedModules_is_enabled, name)
+ }
+ }
+ }
+}
+
+func (c *Checker) checkResolvedBlockScopedVariable(result *Symbol, errorLocation *Node) {
+ //Debug.assert(!!(result.flags&SymbolFlagsBlockScopedVariable || result.flags&SymbolFlagsClass || result.flags&SymbolFlagsEnum))
+ if result.flags&(SymbolFlagsFunction|SymbolFlagsFunctionScopedVariable|SymbolFlagsAssignment) != 0 && result.flags&SymbolFlagsClass != 0 {
+ // constructor functions aren't block scoped
+ return
+ }
+ // Block-scoped variables cannot be used before their definition
+ declaration := find(result.declarations, func(d *Node) bool {
+ return isBlockOrCatchScoped(d) || isClassLike(d) || isEnumDeclaration(d)
+ })
+ if declaration == nil {
+ panic("checkResolvedBlockScopedVariable could not find block-scoped declaration")
+ }
+ if declaration.flags&NodeFlagsAmbient == 0 && !c.isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation) {
+ var diagnostic *Diagnostic
+ declarationName := declarationNameToString(getNameOfDeclaration(declaration))
+ if result.flags&SymbolFlagsBlockScopedVariable != 0 {
+ diagnostic = c.error(errorLocation, diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationName)
+ } else if result.flags&SymbolFlagsClass != 0 {
+ diagnostic = c.error(errorLocation, diagnostics.Class_0_used_before_its_declaration, declarationName)
+ } else if result.flags&SymbolFlagsRegularEnum != 0 {
+ diagnostic = c.error(errorLocation, diagnostics.Enum_0_used_before_its_declaration, declarationName)
+ } else {
+ //Debug.assert(!!(result.flags & SymbolFlagsConstEnum))
+ if getIsolatedModules(c.compilerOptions) {
+ diagnostic = c.error(errorLocation, diagnostics.Enum_0_used_before_its_declaration, declarationName)
+ }
+ }
+ if diagnostic != nil {
+ addRelatedInfo(diagnostic, createDiagnosticForNode(declaration, diagnostics.X_0_is_declared_here, declarationName))
+ }
+ }
+}
+
+func (c *Checker) isBlockScopedNameDeclaredBeforeUse(declaration *Node, usage *Node) bool {
+ return true // !!!
+}
+
+func (c *Checker) checkAndReportErrorForMissingPrefix(errorLocation *Node, name string) bool {
+ return false // !!!
+}
+
+func (c *Checker) getTypeOnlyAliasDeclaration(symbol *Symbol) *Node {
+ return c.getTypeOnlyAliasDeclarationEx(symbol, SymbolFlagsNone)
+}
+
+func (c *Checker) getTypeOnlyAliasDeclarationEx(symbol *Symbol, include SymbolFlags) *Node {
+ if symbol.flags&SymbolFlagsAlias == 0 {
+ return nil
+ }
+ links := c.aliasSymbolLinks.get(symbol)
+ if !links.typeOnlyDeclarationResolved {
+ // We need to set a WIP value here to prevent reentrancy during `getImmediateAliasedSymbol` which, paradoxically, can depend on this
+ links.typeOnlyDeclarationResolved = true
+ resolved := c.resolveSymbol(symbol)
+ // While usually the alias will have been marked during the pass by the full typecheck, we may still need to calculate the alias declaration now
+ var immediateTarget *Symbol
+ if c.getDeclarationOfAliasSymbol(symbol) != nil {
+ immediateTarget = c.getImmediateAliasedSymbol(symbol)
+ }
+ c.markSymbolOfAliasDeclarationIfTypeOnly(symbol.declarations[0], immediateTarget, resolved, true /*overwriteEmpty*/, nil, "")
+ }
+ if include == SymbolFlagsNone {
+ return links.typeOnlyDeclaration
+ }
+ if links.typeOnlyDeclaration != nil {
+ var resolved *Symbol
+ if links.typeOnlyDeclaration.kind == SyntaxKindExportDeclaration {
+ name := links.typeOnlyExportStarName
+ if name == "" {
+ name = symbol.name
+ }
+ resolved = c.resolveSymbol(c.getExportsOfModule(links.typeOnlyDeclaration.Symbol().parent)[name])
+ } else {
+ resolved = c.resolveAlias(links.typeOnlyDeclaration.Symbol())
+ }
+ if c.getSymbolFlags(resolved)&include != 0 {
+ return links.typeOnlyDeclaration
+ }
+ }
+ return nil
+}
+
+func (c *Checker) getImmediateAliasedSymbol(symbol *Symbol) *Symbol {
+ // Debug.assert((symbol.flags&SymbolFlagsAlias) != 0, "Should only get Alias here.")
+ links := c.aliasSymbolLinks.get(symbol)
+ if links.immediateTarget == nil {
+ node := c.getDeclarationOfAliasSymbol(symbol)
+ if node == nil {
+ panic("Unexpected nil in getImmediateAliasedSymbol")
+ }
+ links.immediateTarget = c.getTargetOfAliasDeclaration(node, true /*dontRecursivelyResolve*/)
+ }
+
+ return links.immediateTarget
+}
+
+func (c *Checker) addTypeOnlyDeclarationRelatedInfo(diagnostic *Diagnostic, typeOnlyDeclaration *Node, name string) {
+ // !!!
+}
+
+func (c *Checker) getSymbol(symbols SymbolTable, name string, meaning SymbolFlags) *Symbol {
+ if meaning != 0 {
+ symbol := c.getMergedSymbol(symbols[name])
+ if symbol != nil {
+ if symbol.flags&meaning != 0 {
+ return symbol
+ }
+ if symbol.flags&SymbolFlagsAlias != 0 {
+ targetFlags := c.getSymbolFlags(symbol)
+ // `targetFlags` will be `SymbolFlags.All` if an error occurred in alias resolution; this avoids cascading errors
+ if targetFlags&meaning != 0 {
+ return symbol
+ }
+ }
+ }
+ }
+ // return nil if we can't find a symbol
+ return nil
+}
+
+func (c *Checker) checkSourceFile(sourceFile *SourceFile) {
+ node := sourceFile.AsNode()
+ links := c.nodeLinks.get(node)
+ if links.flags&NodeCheckFlagsTypeChecked == 0 {
+ c.checkSourceElement(node)
+ links.flags |= NodeCheckFlagsTypeChecked
+ }
+}
+
+func (c *Checker) checkSourceElement(node *Node) bool {
+ if node != nil {
+ saveCurrentNode := c.currentNode
+ c.currentNode = node
+ c.instantiationCount = 0
+ c.checkSourceElementWorker(node)
+ c.currentNode = saveCurrentNode
+ }
+ return false
+}
+
+func (c *Checker) checkSourceElementWorker(node *Node) {
+ // !!! Cancellation
+ kind := node.kind
+ if kind >= SyntaxKindFirstStatement && kind <= SyntaxKindLastStatement {
+ flowNode := node.FlowNodeData().flowNode
+ if flowNode != nil && !c.isReachableFlowNode(flowNode) {
+ c.errorOrSuggestion(c.compilerOptions.AllowUnreachableCode == TSFalse, node, diagnostics.Unreachable_code_detected)
+ }
+ }
+ switch node.kind {
+ case SyntaxKindIdentifier:
+ if isExpressionNode(node) &&
+ !(isPropertyAccessExpression(node.parent) && node.parent.AsPropertyAccessExpression().name == node) &&
+ !(isQualifiedName(node.parent) && node.parent.AsQualifiedName().right == node) {
+ c.checkExpression(node)
+ }
+ case SyntaxKindStringLiteral, SyntaxKindNumericLiteral, SyntaxKindBigintLiteral:
+ if isExpressionNode(node) {
+ c.checkExpression(node)
+ }
+ default:
+ node.ForEachChild(c.checkSourceElement)
+ }
+}
+
+/**
+ * Returns the type of an expression. Unlike checkExpression, this function is simply concerned
+ * with computing the type and may not fully check all contained sub-expressions for errors.
+ */
+
+func (c *Checker) getTypeOfExpression(node *Node) *Type {
+ // !!!
+ // // Don't bother caching types that require no flow analysis and are quick to compute.
+ // quickType := c.getQuickTypeOfExpression(node)
+ // if quickType != nil {
+ // return quickType
+ // }
+ // // If a type has been cached for the node, return it.
+ // if node.flags&NodeFlagsTypeCached != 0 {
+ // cachedType := c.flowTypeCache[getNodeId(node)]
+ // if cachedType {
+ // return cachedType
+ // }
+ // }
+ // startInvocationCount := c.flowInvocationCount
+ // t := c.checkExpressionEx(node, CheckModeTypeOnly)
+ // // If control flow analysis was required to determine the type, it is worth caching.
+ // if c.flowInvocationCount != startInvocationCount {
+ // cache := c.flowTypeCache || ( /* TODO(TS-TO-GO) EqualsToken BinaryExpression: flowTypeCache = [] */ TODO)
+ // cache[getNodeId(node)] = t
+ // setNodeFlags(node, node.flags|NodeFlagsTypeCached)
+ // }
+ t := c.checkExpressionEx(node, CheckModeTypeOnly)
+ return t
+}
+
+/**
+ * Returns the type of an expression. Unlike checkExpression, this function is simply concerned
+ * with computing the type and may not fully check all contained sub-expressions for errors.
+ */
+func (c *Checker) getQuickTypeOfExpression(node *Node) *Type {
+ // !!!
+ return nil
+}
+
+func (c *Checker) checkExpressionWithContextualType(node *Node, contextualType *Type, inferenceContext *InferenceContext, checkMode CheckMode) *Type {
+ // !!!
+ return c.checkExpressionEx(node, checkMode)
+}
+
+func (c *Checker) checkExpressionCached(node *Node) *Type {
+ return c.checkExpressionCachedEx(node, CheckModeNormal)
+}
+
+func (c *Checker) checkExpressionCachedEx(node *Node, checkMode CheckMode) *Type {
+ // !!!
+ return c.checkExpressionEx(node, checkMode)
+}
+
+func (c *Checker) checkExpression(node *Node) *Type {
+ return c.checkExpressionEx(node, CheckModeNormal)
+}
+
+func (c *Checker) checkExpressionEx(node *Node, checkMode CheckMode) *Type {
+ saveCurrentNode := c.currentNode
+ c.currentNode = node
+ c.instantiationCount = 0
+ uninstantiatedType := c.checkExpressionWorker(node, checkMode)
+ t := c.instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode)
+ // !!!
+ // if isConstEnumObjectType(typ) {
+ // checkConstEnumAccess(node, typ)
+ // }
+ c.currentNode = saveCurrentNode
+ return t
+}
+
+func (c *Checker) instantiateTypeWithSingleGenericCallSignature(node *Node, uninstantiatedType *Type, checkMode CheckMode) *Type {
+ return uninstantiatedType // !!!
+}
+
+func (c *Checker) checkExpressionWorker(node *Node, checkMode CheckMode) *Type {
+ switch node.kind {
+ case SyntaxKindIdentifier:
+ return c.checkIdentifier(node)
+ case SyntaxKindStringLiteral:
+ // !!! Handle blockedStringType
+ return c.getFreshTypeOfLiteralType(c.getStringLiteralType(node.AsStringLiteral().text))
+ case SyntaxKindNoSubstitutionTemplateLiteral:
+ // !!! Handle blockedStringType
+ return c.getFreshTypeOfLiteralType(c.getStringLiteralType(node.AsNoSubstitutionTemplateLiteral().text))
+ case SyntaxKindNumericLiteral:
+ // !!! checkGrammarNumericLiteral(node as NumericLiteral)
+ value, _ := strconv.ParseFloat(node.AsNumericLiteral().text, 64)
+ return c.getFreshTypeOfLiteralType(c.getNumberLiteralType(value))
+ case SyntaxKindBigintLiteral:
+ // !!! checkGrammarBigIntLiteral(node as BigIntLiteral);
+ return c.getFreshTypeOfLiteralType(c.getBigintLiteralType(PseudoBigint{
+ negative: false,
+ base10Value: parsePseudoBigint(node.AsBigintLiteral().text),
+ }))
+ case SyntaxKindTrueKeyword:
+ return c.trueType
+ case SyntaxKindFalseKeyword:
+ return c.falseType
+ }
+ return c.anyType // !!!
+}
+
+func (c *Checker) checkIdentifier(node *Node) *Type {
+ if isThisInTypeQuery(node) {
+ return c.checkThisExpression(node)
+ }
+ symbol := c.getResolvedSymbol(node)
+ if symbol == c.unknownSymbol {
+ return c.errorType
+ }
+ // !!! c.checkIdentifierCalculateNodeCheckFlags(node, symbol)
+ if symbol == c.argumentsSymbol {
+ if c.isInPropertyInitializerOrClassStaticBlock(node) {
+ return c.errorType
+ }
+ return c.getTypeOfSymbol(symbol)
+ }
+ // !!!
+ // if c.shouldMarkIdentifierAliasReferenced(node) {
+ // c.markLinkedReferences(node, ReferenceHintIdentifier)
+ // }
+ localOrExportSymbol := c.getExportSymbolOfValueSymbolIfExported(symbol)
+ declaration := localOrExportSymbol.valueDeclaration
+ // !!!
+ // immediateDeclaration := declaration
+ // If the identifier is declared in a binding pattern for which we're currently computing the implied type and the
+ // reference occurs with the same binding pattern, return the non-inferrable any type. This for example occurs in
+ // 'const [a, b = a + 1] = [2]' when we're computing the contextual type for the array literal '[2]'.
+ if declaration != nil && declaration.kind == SyntaxKindBindingElement && slices.Contains(c.contextualBindingPatterns, declaration.parent) &&
+ findAncestor(node, func(parent *Node) bool { return parent == declaration.parent }) != nil {
+ return c.nonInferrableAnyType
+ }
+ t := c.getNarrowedTypeOfSymbol(localOrExportSymbol, node)
+ assignmentKind := getAssignmentTargetKind(node)
+ if assignmentKind != AssignmentKindNone {
+ if localOrExportSymbol.flags&SymbolFlagsVariable == 0 {
+ var assignmentError *diagnostics.Message
+ switch {
+ case localOrExportSymbol.flags&SymbolFlagsEnum != 0:
+ assignmentError = diagnostics.Cannot_assign_to_0_because_it_is_an_enum
+ case localOrExportSymbol.flags&SymbolFlagsClass != 0:
+ assignmentError = diagnostics.Cannot_assign_to_0_because_it_is_a_class
+ case localOrExportSymbol.flags&SymbolFlagsModule != 0:
+ assignmentError = diagnostics.Cannot_assign_to_0_because_it_is_a_namespace
+ case localOrExportSymbol.flags&SymbolFlagsFunction != 0:
+ assignmentError = diagnostics.Cannot_assign_to_0_because_it_is_a_function
+ case localOrExportSymbol.flags&SymbolFlagsAlias != 0:
+ assignmentError = diagnostics.Cannot_assign_to_0_because_it_is_an_import
+ default:
+ assignmentError = diagnostics.Cannot_assign_to_0_because_it_is_not_a_variable
+ }
+ c.error(node, assignmentError, c.symbolToString(symbol))
+ return c.errorType
+ }
+ if c.isReadonlySymbol(localOrExportSymbol) {
+ if localOrExportSymbol.flags&SymbolFlagsVariable != 0 {
+ c.error(node, diagnostics.Cannot_assign_to_0_because_it_is_a_constant, c.symbolToString(symbol))
+ } else {
+ c.error(node, diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, c.symbolToString(symbol))
+ }
+ return c.errorType
+ }
+ }
+ isAlias := localOrExportSymbol.flags&SymbolFlagsAlias != 0
+ // We only narrow variables and parameters occurring in a non-assignment position. For all other
+ // entities we simply return the declared type.
+ if localOrExportSymbol.flags&SymbolFlagsVariable != 0 {
+ if assignmentKind == AssignmentKindDefinite {
+ if isInCompoundLikeAssignment(node) {
+ return c.getBaseTypeOfLiteralType(t)
+ }
+ return t
+ }
+ } else if isAlias {
+ declaration = c.getDeclarationOfAliasSymbol(symbol)
+ } else {
+ return t
+ }
+ if declaration == nil {
+ return t
+ }
+ // !!!
+ flowType := t
+ if assignmentKind != AssignmentKindNone {
+ // Identifier is target of a compound assignment
+ return c.getBaseTypeOfLiteralType(flowType)
+ }
+ return flowType
+}
+
+func (c *Checker) isInPropertyInitializerOrClassStaticBlock(node *Node) bool {
+ return findAncestorOrQuit(node, func(node *Node) FindAncestorResult {
+ switch node.kind {
+ case SyntaxKindPropertyDeclaration:
+ return FindAncestorTrue
+ case SyntaxKindPropertyAssignment, SyntaxKindMethodDeclaration, SyntaxKindGetAccessor, SyntaxKindSetAccessor, SyntaxKindSpreadAssignment,
+ SyntaxKindComputedPropertyName, SyntaxKindTemplateSpan, SyntaxKindJsxExpression, SyntaxKindJsxAttribute, SyntaxKindJsxAttributes,
+ SyntaxKindJsxSpreadAttribute, SyntaxKindJsxOpeningElement, SyntaxKindExpressionWithTypeArguments, SyntaxKindHeritageClause:
+ return FindAncestorFalse
+ case SyntaxKindArrowFunction, SyntaxKindExpressionStatement:
+ if isBlock(node.parent) && isClassStaticBlockDeclaration(node.parent.parent) {
+ return FindAncestorTrue
+ }
+ return FindAncestorQuit
+ default:
+ if isExpressionNode(node) {
+ return FindAncestorFalse
+ }
+ return FindAncestorQuit
+ }
+ }) != nil
+}
+
+func (c *Checker) getNarrowedTypeOfSymbol(symbol *Symbol, location *Node) *Type {
+ return c.getTypeOfSymbol(symbol) // !!!
+}
+
+func (c *Checker) isReadonlySymbol(symbol *Symbol) bool {
+ // The following symbols are considered read-only:
+ // Properties with a 'readonly' modifier
+ // Variables declared with 'const'
+ // Get accessors without matching set accessors
+ // Enum members
+ // Object.defineProperty assignments with writable false or no setter
+ // Unions and intersections of the above (unions and intersections eagerly set isReadonly on creation)
+ return symbol.checkFlags&CheckFlagsReadonly != 0 ||
+ symbol.flags&SymbolFlagsProperty != 0 && getDeclarationModifierFlagsFromSymbol(symbol, false /*isWrite*/)&ModifierFlagsReadonly != 0 ||
+ symbol.flags&SymbolFlagsVariable != 0 && c.getDeclarationNodeFlagsFromSymbol(symbol)&NodeFlagsConstant != 0 ||
+ symbol.flags&SymbolFlagsAccessor != 0 && symbol.flags&SymbolFlagsSetAccessor == 0 ||
+ symbol.flags&SymbolFlagsEnumMember != 0
+}
+
+func (c *Checker) checkThisExpression(node *Node) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) checkObjectLiteralMethod(node *MethodDeclaration, checkMode CheckMode) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) checkPropertyAssignment(node *PropertyAssignment, checkMode CheckMode) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) checkJsxAttribute(node *JsxAttribute, checkMode CheckMode) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) checkExpressionForMutableLocation(node *Node, checkMode CheckMode) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) getResolvedSymbol(node *Node) *Symbol {
+ links := c.nodeLinks.get(node)
+ if links.resolvedSymbol == nil {
+ var symbol *Symbol
+ if !nodeIsMissing(node) {
+ symbol = c.resolveName(node, node.AsIdentifier().text, SymbolFlagsValue|SymbolFlagsExportValue,
+ c.getCannotFindNameDiagnosticForName(node), !isWriteOnlyAccess(node), false /*excludeGlobals*/)
+ }
+ if symbol == nil {
+ symbol = c.unknownSymbol
+ }
+ links.resolvedSymbol = symbol
+ }
+ return links.resolvedSymbol
+}
+
+func isWriteOnlyAccess(node *Node) bool {
+ return false // !!!
+}
+
+func (c *Checker) getCannotFindNameDiagnosticForName(node *Node) *diagnostics.Message {
+ switch node.AsIdentifier().text {
+ case "document", "console":
+ return diagnostics.Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_include_dom
+ case "$":
+ return ifElse(c.compilerOptions.Types != nil,
+ diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery_and_then_add_jquery_to_the_types_field_in_your_tsconfig,
+ diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery)
+ case "describe", "suite", "it", "test":
+ return ifElse(c.compilerOptions.Types != nil,
+ diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha_and_then_add_jest_or_mocha_to_the_types_field_in_your_tsconfig,
+ diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha)
+ case "process", "require", "Buffer", "module":
+ return ifElse(c.compilerOptions.Types != nil,
+ diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode_and_then_add_node_to_the_types_field_in_your_tsconfig,
+ diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode)
+ case "Bun":
+ return ifElse(c.compilerOptions.Types != nil,
+ diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_Bun_Try_npm_i_save_dev_types_Slashbun_and_then_add_bun_to_the_types_field_in_your_tsconfig,
+ diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_Bun_Try_npm_i_save_dev_types_Slashbun)
+ case "Map", "Set", "Promise", "Symbol", "WeakMap", "WeakSet", "Iterator", "AsyncIterator", "SharedArrayBuffer", "Atomics", "AsyncIterable",
+ "AsyncIterableIterator", "AsyncGenerator", "AsyncGeneratorFunction", "BigInt", "Reflect", "BigInt64Array", "BigUint64Array":
+ return diagnostics.Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_1_or_later
+ case "await":
+ if isCallExpression(node.parent) {
+ return diagnostics.Cannot_find_name_0_Did_you_mean_to_write_this_in_an_async_function
+ }
+ fallthrough
+ default:
+ if node.parent.kind == SyntaxKindShorthandPropertyAssignment {
+ return diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer
+ }
+ return diagnostics.Cannot_find_name_0
+ }
+}
+
+func (c *Checker) isReachableFlowNode(flowNode *FlowNode) bool {
+ return true // !!!
+}
+
+func (c *Checker) GetDiagnostics(sourceFile *SourceFile) []*Diagnostic {
+ if sourceFile != nil {
+ c.checkSourceFile(sourceFile)
+ return c.diagnostics.GetDiagnosticsForFile(sourceFile.fileName)
+ }
+ for _, file := range c.files {
+ c.checkSourceFile(file)
+ }
+ return c.diagnostics.GetDiagnostics()
+}
+
+func (c *Checker) GetGlobalDiagnostics() []*Diagnostic {
+ return c.diagnostics.GetGlobalDiagnostics()
+}
+
+func (c *Checker) error(location *Node, message *diagnostics.Message, args ...any) *Diagnostic {
+ diagnostic := NewDiagnosticForNode(location, message, args...)
+ c.diagnostics.add(diagnostic)
+ return diagnostic
+}
+
+func (c *Checker) errorOrSuggestion(isError bool, location *Node, message *diagnostics.Message, args ...any) {
+ c.addErrorOrSuggestion(isError, NewDiagnosticForNode(location, message, args...))
+}
+
+func (c *Checker) addErrorOrSuggestion(isError bool, diagnostic *Diagnostic) {
+ if isError {
+ c.diagnostics.add(diagnostic)
+ } else {
+ suggestion := *diagnostic
+ suggestion.category = diagnostics.CategorySuggestion
+ c.suggestionDiagnostics.add(&suggestion)
+ }
+}
+
+func (c *Checker) newSymbol(flags SymbolFlags, name string) *Symbol {
+ c.symbolCount++
+ result := c.symbolPool.New()
+ result.flags = flags | SymbolFlagsTransient
+ result.name = name
+ return result
+}
+
+func (c *Checker) newSymbolEx(flags SymbolFlags, name string, checkFlags CheckFlags) *Symbol {
+ result := c.newSymbol(flags, name)
+ result.checkFlags = checkFlags
+ return result
+}
+
+func (c *Checker) mergeSymbolTable(target SymbolTable, source SymbolTable, unidirectional bool, mergedParent *Symbol) {
+ for id, sourceSymbol := range source {
+ targetSymbol := target[id]
+ var merged *Symbol
+ if targetSymbol != nil {
+ merged = c.mergeSymbol(targetSymbol, sourceSymbol, unidirectional)
+ } else {
+ merged = c.getMergedSymbol(sourceSymbol)
+ }
+ if mergedParent != nil && targetSymbol != nil {
+ // If a merge was performed on the target symbol, set its parent to the merged parent that initiated the merge
+ // of its exports. Otherwise, `merged` came only from `sourceSymbol` and can keep its parent:
+ //
+ // // a.ts
+ // export interface A { x: number; }
+ //
+ // // b.ts
+ // declare module "./a" {
+ // interface A { y: number; }
+ // interface B {}
+ // }
+ //
+ // When merging the module augmentation into a.ts, the symbol for `A` will itself be merged, so its parent
+ // should be the merged module symbol. But the symbol for `B` has only one declaration, so its parent should
+ // be the module augmentation symbol, which contains its only declaration.
+ merged.parent = mergedParent
+ }
+ target[id] = merged
+ }
+}
+
+/**
+ * Note: if target is transient, then it is mutable, and mergeSymbol with both mutate and return it.
+ * If target is not transient, mergeSymbol will produce a transient clone, mutate that and return it.
+ */
+func (c *Checker) mergeSymbol(target *Symbol, source *Symbol, unidirectional bool) *Symbol {
+ if target.flags&getExcludedSymbolFlags(source.flags) == 0 || (source.flags|target.flags)&SymbolFlagsAssignment != 0 {
+ if source == target {
+ // This can happen when an export assigned namespace exports something also erroneously exported at the top level
+ // See `declarationFileNoCrashOnExtraExportModifier` for an example
+ return target
+ }
+ if target.flags&SymbolFlagsTransient == 0 {
+ resolvedTarget := c.resolveSymbol(target)
+ if resolvedTarget == c.unknownSymbol {
+ return source
+ }
+ if resolvedTarget.flags&getExcludedSymbolFlags(source.flags) == 0 || (source.flags|resolvedTarget.flags)&SymbolFlagsAssignment != 0 {
+ target = c.cloneSymbol(resolvedTarget)
+ } else {
+ c.reportMergeSymbolError(target, source)
+ return source
+ }
+ }
+ // Javascript static-property-assignment declarations always merge, even though they are also values
+ if source.flags&SymbolFlagsValueModule != 0 && target.flags&SymbolFlagsValueModule != 0 && target.constEnumOnlyModule && !source.constEnumOnlyModule {
+ // reset flag when merging instantiated module into value module that has only const enums
+ target.constEnumOnlyModule = false
+ }
+ target.flags |= source.flags
+ if source.valueDeclaration != nil {
+ setValueDeclaration(target, source.valueDeclaration)
+ }
+ target.declarations = append(target.declarations, source.declarations...)
+ if source.members != nil {
+ if target.members == nil {
+ target.members = make(SymbolTable)
+ }
+ c.mergeSymbolTable(target.members, source.members, unidirectional, nil)
+ }
+ if source.exports != nil {
+ if target.exports == nil {
+ target.exports = make(SymbolTable)
+ }
+ c.mergeSymbolTable(target.exports, source.exports, unidirectional, target)
+ }
+ if !unidirectional {
+ c.recordMergedSymbol(target, source)
+ }
+ } else if target.flags&SymbolFlagsNamespaceModule != 0 {
+ // Do not report an error when merging `var globalThis` with the built-in `globalThis`,
+ // as we will already report a "Declaration name conflicts..." error, and this error
+ // won't make much sense.
+ if target != c.globalThisSymbol {
+ c.error(getNameOfDeclaration(getFirstDeclaration(source)), diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, c.symbolToString(target))
+ }
+ } else {
+ c.reportMergeSymbolError(target, source)
+ }
+ return target
+}
+
+func (c *Checker) reportMergeSymbolError(target *Symbol, source *Symbol) {
+ isEitherEnum := target.flags&SymbolFlagsEnum != 0 || source.flags&SymbolFlagsEnum != 0
+ isEitherBlockScoped := target.flags&SymbolFlagsBlockScopedVariable != 0 || source.flags&SymbolFlagsBlockScopedVariable != 0
+ var message *diagnostics.Message
+ switch {
+ case isEitherEnum:
+ message = diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations
+ case isEitherBlockScoped:
+ message = diagnostics.Cannot_redeclare_block_scoped_variable_0
+ default:
+ message = diagnostics.Duplicate_identifier_0
+ }
+ // sourceSymbolFile := getSourceFileOfNode(getFirstDeclaration(source))
+ // targetSymbolFile := getSourceFileOfNode(getFirstDeclaration(target))
+ symbolName := c.symbolToString(source)
+ // !!!
+ // Collect top-level duplicate identifier errors into one mapping, so we can then merge their diagnostics if there are a bunch
+ // if sourceSymbolFile != nil && targetSymbolFile != nil && c.amalgamatedDuplicates && !isEitherEnum && sourceSymbolFile != targetSymbolFile {
+ // var firstFile SourceFile
+ // if comparePaths(sourceSymbolFile.path, targetSymbolFile.path) == ComparisonLessThan {
+ // firstFile = sourceSymbolFile
+ // } else {
+ // firstFile = targetSymbolFile
+ // }
+ // var secondFile SourceFile
+ // if firstFile == sourceSymbolFile {
+ // secondFile = targetSymbolFile
+ // } else {
+ // secondFile = sourceSymbolFile
+ // }
+ // filesDuplicates := getOrUpdate(c.amalgamatedDuplicates, __TEMPLATE__(firstFile.path, "|", secondFile.path), func() DuplicateInfoForFiles {
+ // return (map[any]any{ /* TODO(TS-TO-GO): was object literal */
+ // "firstFile": firstFile,
+ // "secondFile": secondFile,
+ // "conflictingSymbols": NewMap(),
+ // })
+ // })
+ // conflictingSymbolInfo := getOrUpdate(filesDuplicates.conflictingSymbols, symbolName, func() DuplicateInfoForSymbol {
+ // return (map[any]any{ /* TODO(TS-TO-GO): was object literal */
+ // "isBlockScoped": isEitherBlockScoped,
+ // "firstFileLocations": []never{},
+ // "secondFileLocations": []never{},
+ // })
+ // })
+ // if !isSourcePlainJs {
+ // addDuplicateLocations(conflictingSymbolInfo.firstFileLocations, source)
+ // }
+ // if !isTargetPlainJs {
+ // addDuplicateLocations(conflictingSymbolInfo.secondFileLocations, target)
+ // }
+ // } else {
+ c.addDuplicateDeclarationErrorsForSymbols(source, message, symbolName, target)
+ c.addDuplicateDeclarationErrorsForSymbols(target, message, symbolName, source)
+}
+
+func (c *Checker) addDuplicateDeclarationErrorsForSymbols(target *Symbol, message *diagnostics.Message, symbolName string, source *Symbol) {
+ for _, node := range target.declarations {
+ c.addDuplicateDeclarationError(node, message, symbolName, source.declarations)
+ }
+}
+
+func (c *Checker) addDuplicateDeclarationError(node *Node, message *diagnostics.Message, symbolName string, relatedNodes []*Node) {
+ errorNode := getAdjustedNodeForError(node)
+ if errorNode == nil {
+ errorNode = node
+ }
+ err := c.lookupOrIssueError(errorNode, message, symbolName)
+ for _, relatedNode := range relatedNodes {
+ adjustedNode := getAdjustedNodeForError(relatedNode)
+ if adjustedNode == errorNode {
+ continue
+ }
+ leadingMessage := createDiagnosticForNode(adjustedNode, diagnostics.X_0_was_also_declared_here, symbolName)
+ followOnMessage := createDiagnosticForNode(adjustedNode, diagnostics.X_and_here)
+ if len(err.relatedInformation) >= 5 || some(err.relatedInformation, func(d *Diagnostic) bool {
+ return compareDiagnostics(d, followOnMessage) == 0 || compareDiagnostics(d, leadingMessage) == 0
+ }) {
+ continue
+ }
+ if len(err.relatedInformation) == 0 {
+ addRelatedInfo(err, leadingMessage)
+ } else {
+ addRelatedInfo(err, followOnMessage)
+ }
+ }
+}
+
+func createDiagnosticForNode(node *Node, message *diagnostics.Message, args ...any) *Diagnostic {
+ return NewDiagnostic(getSourceFileOfNode(node), node.loc, message, args...)
+}
+
+func getAdjustedNodeForError(node *Node) *Node {
+ return getNameOfDeclaration(node)
+}
+
+func (c *Checker) lookupOrIssueError(location *Node, message *diagnostics.Message, args ...any) *Diagnostic {
+ var file *SourceFile
+ var loc TextRange
+ if location != nil {
+ file = getSourceFileOfNode(location)
+ loc = location.loc
+ }
+ diagnostic := NewDiagnostic(file, loc, message, args...)
+ existing := c.diagnostics.lookup(diagnostic)
+ if existing != nil {
+ return existing
+ }
+ c.diagnostics.add(diagnostic)
+ return diagnostic
+}
+
+func getFirstDeclaration(symbol *Symbol) *Node {
+ if len(symbol.declarations) > 0 {
+ return symbol.declarations[0]
+ }
+ return nil
+}
+
+func getExcludedSymbolFlags(flags SymbolFlags) SymbolFlags {
+ var result SymbolFlags
+ if flags&SymbolFlagsBlockScopedVariable != 0 {
+ result |= SymbolFlagsBlockScopedVariableExcludes
+ }
+ if flags&SymbolFlagsFunctionScopedVariable != 0 {
+ result |= SymbolFlagsFunctionScopedVariableExcludes
+ }
+ if flags&SymbolFlagsProperty != 0 {
+ result |= SymbolFlagsPropertyExcludes
+ }
+ if flags&SymbolFlagsEnumMember != 0 {
+ result |= SymbolFlagsEnumMemberExcludes
+ }
+ if flags&SymbolFlagsFunction != 0 {
+ result |= SymbolFlagsFunctionExcludes
+ }
+ if flags&SymbolFlagsClass != 0 {
+ result |= SymbolFlagsClassExcludes
+ }
+ if flags&SymbolFlagsInterface != 0 {
+ result |= SymbolFlagsInterfaceExcludes
+ }
+ if flags&SymbolFlagsRegularEnum != 0 {
+ result |= SymbolFlagsRegularEnumExcludes
+ }
+ if flags&SymbolFlagsConstEnum != 0 {
+ result |= SymbolFlagsConstEnumExcludes
+ }
+ if flags&SymbolFlagsValueModule != 0 {
+ result |= SymbolFlagsValueModuleExcludes
+ }
+ if flags&SymbolFlagsMethod != 0 {
+ result |= SymbolFlagsMethodExcludes
+ }
+ if flags&SymbolFlagsGetAccessor != 0 {
+ result |= SymbolFlagsGetAccessorExcludes
+ }
+ if flags&SymbolFlagsSetAccessor != 0 {
+ result |= SymbolFlagsSetAccessorExcludes
+ }
+ if flags&SymbolFlagsTypeParameter != 0 {
+ result |= SymbolFlagsTypeParameterExcludes
+ }
+ if flags&SymbolFlagsTypeAlias != 0 {
+ result |= SymbolFlagsTypeAliasExcludes
+ }
+ if flags&SymbolFlagsAlias != 0 {
+ result |= SymbolFlagsAliasExcludes
+ }
+ return result
+}
+
+func (c *Checker) cloneSymbol(symbol *Symbol) *Symbol {
+ result := c.newSymbol(symbol.flags, symbol.name)
+ // Force reallocation if anything is ever appended to declarations
+ result.declarations = symbol.declarations[0:len(symbol.declarations):len(symbol.declarations)]
+ result.parent = symbol.parent
+ result.valueDeclaration = symbol.valueDeclaration
+ result.constEnumOnlyModule = symbol.constEnumOnlyModule
+ result.members = maps.Clone(symbol.members)
+ result.exports = maps.Clone(symbol.exports)
+ c.recordMergedSymbol(result, symbol)
+ return result
+}
+
+func (c *Checker) getMergedSymbol(symbol *Symbol) *Symbol {
+ // If a symbol was never merged it will have a zero mergeId
+ if symbol != nil && symbol.mergeId != 0 {
+ merged := c.mergedSymbols[symbol.mergeId]
+ if merged != nil {
+ return merged
+ }
+ }
+ return symbol
+}
+
+func (c *Checker) getParentOfSymbol(symbol *Symbol) *Symbol {
+ if symbol.parent != nil {
+ return c.getMergedSymbol(c.getLateBoundSymbol(symbol.parent))
+ }
+ return nil
+}
+
+func (c *Checker) recordMergedSymbol(target *Symbol, source *Symbol) {
+ c.mergedSymbols[getMergeId(source)] = target
+}
+
+func (c *Checker) getSymbolIfSameReference(s1 *Symbol, s2 *Symbol) *Symbol {
+ if c.getMergedSymbol(c.resolveSymbol(c.getMergedSymbol(s1))) == c.getMergedSymbol(c.resolveSymbol(c.getMergedSymbol(s2))) {
+ return s1
+ }
+ return nil
+}
+
+func (c *Checker) getExportSymbolOfValueSymbolIfExported(symbol *Symbol) *Symbol {
+ if symbol != nil && symbol.flags&SymbolFlagsExportValue != 0 && symbol.exportSymbol != nil {
+ symbol = symbol.exportSymbol
+ }
+ return c.getMergedSymbol(symbol)
+}
+
+func (c *Checker) getSymbolOfDeclaration(node *Node) *Symbol {
+ symbol := node.Symbol()
+ if symbol != nil {
+ return c.getMergedSymbol(c.getLateBoundSymbol(symbol))
+ }
+ return nil
+}
+
+func (c *Checker) getLateBoundSymbol(symbol *Symbol) *Symbol {
+ return symbol // !!!
+}
+
+func (c *Checker) resolveSymbol(symbol *Symbol) *Symbol {
+ return c.resolveSymbolEx(symbol, false /*dontResolveAlias*/)
+}
+
+func (c *Checker) resolveSymbolEx(symbol *Symbol, dontResolveAlias bool) *Symbol {
+ if !dontResolveAlias && isNonLocalAlias(symbol, SymbolFlagsValue|SymbolFlagsType|SymbolFlagsNamespace) {
+ return c.resolveAlias(symbol)
+ }
+ return symbol
+}
+
+func (c *Checker) getTargetOfImportEqualsDeclaration(node *Node, dontResolveAlias bool) *Symbol {
+ // Node is ImportEqualsDeclaration | VariableDeclaration
+ commonJSPropertyAccess := c.getCommonJSPropertyAccess(node)
+ if commonJSPropertyAccess != nil {
+ access := commonJSPropertyAccess.AsPropertyAccessExpression()
+ name := getLeftmostAccessExpression(access.expression).AsCallExpression().arguments[0]
+ if isIdentifier(access.name) {
+ return c.resolveSymbol(c.getPropertyOfType(c.resolveExternalModuleTypeByLiteral(name), getTextOfIdentifierOrLiteral(access.name)))
+ }
+ return nil
+ }
+ if isVariableDeclaration(node) || node.AsImportEqualsDeclaration().moduleReference.kind == SyntaxKindExternalModuleReference {
+ moduleReference := getExternalModuleRequireArgument(node)
+ if moduleReference == nil {
+ moduleReference = getExternalModuleImportEqualsDeclarationExpression(node)
+ }
+ immediate := c.resolveExternalModuleName(node, moduleReference, false /*ignoreErrors*/)
+ resolved := c.resolveExternalModuleSymbol(immediate, false /*dontResolveAlias*/)
+ c.markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, false /*overwriteEmpty*/, nil, "")
+ return resolved
+ }
+ resolved := c.getSymbolOfPartOfRightHandSideOfImportEquals(node.AsImportEqualsDeclaration().moduleReference, dontResolveAlias)
+ c.checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node, resolved)
+ return resolved
+}
+
+func (c *Checker) getCommonJSPropertyAccess(node *Node) *Node {
+ if isVariableDeclaration(node) {
+ decl := node.AsVariableDeclaration()
+ if decl.initializer != nil && isPropertyAccessExpression(decl.initializer) {
+ return decl.initializer
+ }
+ }
+ return nil
+}
+
+func (c *Checker) resolveExternalModuleTypeByLiteral(name *Node) *Type {
+ moduleSym := c.resolveExternalModuleName(name, name, false /*ignoreErrors*/)
+ if moduleSym != nil {
+ resolvedModuleSymbol := c.resolveExternalModuleSymbol(moduleSym, false /*dontResolveAlias*/)
+ if resolvedModuleSymbol != nil {
+ return c.getTypeOfSymbol(resolvedModuleSymbol)
+ }
+ }
+ return c.anyType
+}
+
+// This function is only for imports with entity names
+func (c *Checker) getSymbolOfPartOfRightHandSideOfImportEquals(entityName *Node, dontResolveAlias bool) *Symbol {
+ // There are three things we might try to look for. In the following examples,
+ // the search term is enclosed in |...|:
+ //
+ // import a = |b|; // Namespace
+ // import a = |b.c|; // Value, type, namespace
+ // import a = |b.c|.d; // Namespace
+ if entityName.kind == SyntaxKindIdentifier && isRightSideOfQualifiedNameOrPropertyAccess(entityName) {
+ entityName = entityName.parent // QualifiedName
+ }
+ // Check for case 1 and 3 in the above example
+ if entityName.kind == SyntaxKindIdentifier || entityName.parent.kind == SyntaxKindQualifiedName {
+ return c.resolveEntityName(entityName, SymbolFlagsNamespace, false /*ignoreErrors*/, dontResolveAlias, nil /*location*/)
+ }
+ // Case 2 in above example
+ // entityName.kind could be a QualifiedName or a Missing identifier
+ //Debug.assert(entityName.parent.kind == SyntaxKindImportEqualsDeclaration)
+ return c.resolveEntityName(entityName, SymbolFlagsValue|SymbolFlagsType|SymbolFlagsNamespace, false /*ignoreErrors*/, dontResolveAlias, nil /*location*/)
+}
+
+func (c *Checker) checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node *Node, resolved *Symbol) {
+ decl := node.AsImportEqualsDeclaration()
+ if c.markSymbolOfAliasDeclarationIfTypeOnly(node, nil /*immediateTarget*/, resolved, false /*overwriteEmpty*/, nil, "") && !decl.isTypeOnly {
+ typeOnlyDeclaration := c.getTypeOnlyAliasDeclaration(c.getSymbolOfDeclaration(node))
+ isExport := nodeKindIs(typeOnlyDeclaration, SyntaxKindExportSpecifier, SyntaxKindExportDeclaration)
+ message := ifElse(isExport,
+ diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_exported_using_export_type,
+ diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_imported_using_import_type)
+ relatedMessage := ifElse(isExport,
+ diagnostics.X_0_was_exported_here,
+ diagnostics.X_0_was_imported_here)
+ // TODO: how to get name for export *?
+ name := "*"
+ if typeOnlyDeclaration.kind == SyntaxKindImportDeclaration {
+ name = getNameFromImportDeclaration(typeOnlyDeclaration).AsIdentifier().text
+ }
+ addRelatedInfo(c.error(decl.moduleReference, message), createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name))
+ }
+}
+
+func (c *Checker) getTargetOfImportClause(node *Node, dontResolveAlias bool) *Symbol {
+ moduleSymbol := c.resolveExternalModuleName(node, getModuleSpecifierFromNode(node.parent), false /*ignoreErrors*/)
+ if moduleSymbol != nil {
+ return c.getTargetOfModuleDefault(moduleSymbol, node, dontResolveAlias)
+ }
+ return nil
+}
+
+func (c *Checker) getTargetOfModuleDefault(moduleSymbol *Symbol, node *Node, dontResolveAlias bool) *Symbol {
+ var exportDefaultSymbol *Symbol
+ if isShorthandAmbientModuleSymbol(moduleSymbol) {
+ exportDefaultSymbol = moduleSymbol
+ } else {
+ exportDefaultSymbol = c.resolveExportByName(moduleSymbol, InternalSymbolNameDefault, node, dontResolveAlias)
+ }
+ // !!!
+ // file := find(moduleSymbol.declarations, isSourceFile)
+ // specifier := c.getModuleSpecifierForImportOrExport(node)
+ // if specifier == nil {
+ // return exportDefaultSymbol
+ // }
+ // hasDefaultOnly := c.isOnlyImportableAsDefault(specifier, moduleSymbol)
+ // hasSyntheticDefault := c.canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, specifier)
+ // if !exportDefaultSymbol && !hasSyntheticDefault && !hasDefaultOnly {
+ // if c.hasExportAssignmentSymbol(moduleSymbol) && !c.allowSyntheticDefaultImports {
+ // var compilerOptionName /* TODO(TS-TO-GO) inferred type "allowSyntheticDefaultImports" | "esModuleInterop" */ any
+ // if c.moduleKind >= ModuleKindES2015 {
+ // compilerOptionName = "allowSyntheticDefaultImports"
+ // } else {
+ // compilerOptionName = "esModuleInterop"
+ // }
+ // exportEqualsSymbol := moduleSymbol.exports.get(InternalSymbolNameExportEquals)
+ // exportAssignment := exportEqualsSymbol.valueDeclaration
+ // err := c.error(node.name, Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, c.symbolToString(moduleSymbol), compilerOptionName)
+
+ // if exportAssignment {
+ // addRelatedInfo(err, createDiagnosticForNode(exportAssignment, Diagnostics.This_module_is_declared_with_export_and_can_only_be_used_with_a_default_import_when_using_the_0_flag, compilerOptionName))
+ // }
+ // } else if isImportClause(node) {
+ // c.reportNonDefaultExport(moduleSymbol, node)
+ // } else {
+ // c.errorNoModuleMemberSymbol(moduleSymbol, moduleSymbol, node, isImportOrExportSpecifier(node) && node.propertyName || node.name)
+ // }
+ // } else if hasSyntheticDefault || hasDefaultOnly {
+ // // per emit behavior, a synthetic default overrides a "real" .default member if `__esModule` is not present
+ // resolved := c.resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || c.resolveSymbol(moduleSymbol, dontResolveAlias)
+ // c.markSymbolOfAliasDeclarationIfTypeOnly(node, moduleSymbol, resolved /*overwriteEmpty*/, false)
+ // return resolved
+ // }
+ // c.markSymbolOfAliasDeclarationIfTypeOnly(node, exportDefaultSymbol /*finalTarget*/, nil /*overwriteEmpty*/, false)
+ return exportDefaultSymbol
+}
+
+func (c *Checker) resolveExportByName(moduleSymbol *Symbol, name string, sourceNode *Node, dontResolveAlias bool) *Symbol {
+ exportValue := moduleSymbol.exports[InternalSymbolNameExportEquals]
+ var exportSymbol *Symbol
+ if exportValue != nil {
+ exportSymbol = c.getPropertyOfTypeEx(c.getTypeOfSymbol(exportValue), name, true /*skipObjectFunctionPropertyAugment*/, false /*includeTypeOnlyMembers*/)
+ } else {
+ exportSymbol = moduleSymbol.exports[name]
+ }
+ resolved := c.resolveSymbolEx(exportSymbol, dontResolveAlias)
+ c.markSymbolOfAliasDeclarationIfTypeOnly(sourceNode, exportSymbol, resolved, false /*overwriteEmpty*/, nil, "")
+ return resolved
+}
+
+func (c *Checker) getTargetOfNamespaceImport(node *Node, dontResolveAlias bool) *Symbol {
+ moduleSpecifier := c.getModuleSpecifierForImportOrExport(node)
+ immediate := c.resolveExternalModuleName(node, moduleSpecifier, false /*ignoreErrors*/)
+ resolved := c.resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias /*suppressInteropError*/, false)
+ c.markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, false /*overwriteEmpty*/, nil, "")
+ return resolved
+}
+
+func (c *Checker) getTargetOfNamespaceExport(node *Node, dontResolveAlias bool) *Symbol {
+ moduleSpecifier := c.getModuleSpecifierForImportOrExport(node)
+ if moduleSpecifier != nil {
+ immediate := c.resolveExternalModuleName(node, moduleSpecifier, false /*ignoreErrors*/)
+ resolved := c.resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias /*suppressInteropError*/, false)
+ c.markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, false /*overwriteEmpty*/, nil, "")
+ return resolved
+ }
+ return nil
+}
+
+func (c *Checker) getTargetOfImportSpecifier(node *Node, dontResolveAlias bool) *Symbol {
+ name := node.AsImportSpecifier().propertyName
+ if name == nil {
+ name = node.AsImportSpecifier().name
+ }
+ if moduleExportNameIsDefault(name) {
+ specifier := c.getModuleSpecifierForImportOrExport(node)
+ if specifier != nil {
+ moduleSymbol := c.resolveExternalModuleName(node, specifier, false /*ignoreErrors*/)
+ if moduleSymbol != nil {
+ return c.getTargetOfModuleDefault(moduleSymbol, node, dontResolveAlias)
+ }
+ }
+ }
+ root := node.parent.parent.parent // ImportDeclaration
+ resolved := c.getExternalModuleMember(root, node, dontResolveAlias)
+ c.markSymbolOfAliasDeclarationIfTypeOnly(node, nil /*immediateTarget*/, resolved, false /*overwriteEmpty*/, nil, "")
+ return resolved
+}
+
+func (c *Checker) getExternalModuleMember(node *Node, specifier *Node, dontResolveAlias bool) *Symbol {
+ // node is ImportDeclaration | ExportDeclaration | VariableDeclaration
+ // specifier is ImportSpecifier | ExportSpecifier | BindingElement | PropertyAccessExpression
+ moduleSpecifier := getExternalModuleRequireArgument(node)
+ if moduleSpecifier == nil {
+ moduleSpecifier = getExternalModuleName(node)
+ }
+ moduleSymbol := c.resolveExternalModuleName(node, moduleSpecifier, false /*ignoreErrors*/)
+ var name *Node
+ if !isPropertyAccessExpression(specifier) {
+ name = getPropertyNameFromSpecifier(specifier)
+ }
+ if name == nil {
+ name = getNameFromSpecifier(specifier)
+ }
+ if !isIdentifier(name) && !isStringLiteral(name) {
+ return nil
+ }
+ nameText := getTextOfIdentifierOrLiteral(name)
+ suppressInteropError := nameText == InternalSymbolNameDefault && c.allowSyntheticDefaultImports
+ targetSymbol := c.resolveESModuleSymbol(moduleSymbol, moduleSpecifier /*dontResolveAlias*/, false, suppressInteropError)
+ if targetSymbol != nil {
+ // Note: The empty string is a valid module export name:
+ //
+ // import { "" as foo } from "./foo";
+ // export { foo as "" };
+ //
+ if nameText != "" || name.kind == SyntaxKindStringLiteral {
+ if isShorthandAmbientModuleSymbol(moduleSymbol) {
+ return moduleSymbol
+ }
+ var symbolFromVariable *Symbol
+ // First check if module was specified with "export=". If so, get the member from the resolved type
+ if moduleSymbol != nil && moduleSymbol.exports[InternalSymbolNameExportEquals] != nil {
+ symbolFromVariable = c.getPropertyOfTypeEx(c.getTypeOfSymbol(targetSymbol), nameText, true /*skipObjectFunctionPropertyAugment*/, false /*includeTypeOnlyMembers*/)
+ } else {
+ symbolFromVariable = c.getPropertyOfVariable(targetSymbol, nameText)
+ }
+ // if symbolFromVariable is export - get its final target
+ symbolFromVariable = c.resolveSymbolEx(symbolFromVariable, dontResolveAlias)
+ symbolFromModule := c.getExportOfModule(targetSymbol, nameText, specifier, dontResolveAlias)
+ if symbolFromModule == nil && nameText == InternalSymbolNameDefault {
+ file := find(moduleSymbol.declarations, isSourceFile)
+ if c.isOnlyImportableAsDefault(moduleSpecifier, moduleSymbol) || c.canHaveSyntheticDefault(file.AsSourceFile(), moduleSymbol, dontResolveAlias, moduleSpecifier) {
+ symbolFromModule = c.resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias)
+ if symbolFromModule == nil {
+ symbolFromModule = c.resolveSymbolEx(moduleSymbol, dontResolveAlias)
+ }
+ }
+ }
+ symbol := symbolFromVariable
+ if symbolFromModule != nil {
+ symbol = symbolFromModule
+ if symbolFromVariable != nil {
+ symbol = c.combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule)
+ }
+ }
+ if isImportOrExportSpecifier(specifier) && c.isOnlyImportableAsDefault(moduleSpecifier, moduleSymbol) && nameText != InternalSymbolNameDefault {
+ // !!!
+ // c.error(name, Diagnostics.Named_imports_from_a_JSON_file_into_an_ECMAScript_module_are_not_allowed_when_module_is_set_to_0, ModuleKind[c.moduleKind])
+ } else if symbol == nil {
+ c.errorNoModuleMemberSymbol(moduleSymbol, targetSymbol, node, name)
+ }
+ return symbol
+ }
+ }
+ return nil
+}
+
+func (c *Checker) getPropertyOfVariable(symbol *Symbol, name string) *Symbol {
+ if symbol.flags&SymbolFlagsVariable != 0 {
+ typeAnnotation := symbol.valueDeclaration.AsVariableDeclaration().typeNode
+ if typeAnnotation != nil {
+ return c.resolveSymbol(c.getPropertyOfType(c.getTypeFromTypeNode(typeAnnotation), name))
+ }
+ }
+ return nil
+}
+
+// This function creates a synthetic symbol that combines the value side of one symbol with the
+// type/namespace side of another symbol. Consider this example:
+//
+// declare module graphics {
+// interface Point {
+// x: number;
+// y: number;
+// }
+// }
+// declare var graphics: {
+// Point: new (x: number, y: number) => graphics.Point;
+// }
+// declare module "graphics" {
+// export = graphics;
+// }
+//
+// An 'import { Point } from "graphics"' needs to create a symbol that combines the value side 'Point'
+// property with the type/namespace side interface 'Point'.
+func (c *Checker) combineValueAndTypeSymbols(valueSymbol *Symbol, typeSymbol *Symbol) *Symbol {
+ if valueSymbol == c.unknownSymbol && typeSymbol == c.unknownSymbol {
+ return c.unknownSymbol
+ }
+ if valueSymbol.flags&(SymbolFlagsType|SymbolFlagsNamespace) != 0 {
+ return valueSymbol
+ }
+ result := c.newSymbol(valueSymbol.flags|typeSymbol.flags, valueSymbol.name)
+ //Debug.assert(valueSymbol.declarations || typeSymbol.declarations)
+ result.declarations = slices.Compact(slices.Concat(valueSymbol.declarations, typeSymbol.declarations))
+ result.parent = valueSymbol.parent
+ if result.parent == nil {
+ result.parent = typeSymbol.parent
+ }
+ result.valueDeclaration = valueSymbol.valueDeclaration
+ result.members = maps.Clone(typeSymbol.members)
+ result.exports = maps.Clone(valueSymbol.exports)
+ return result
+}
+
+func (c *Checker) getExportOfModule(symbol *Symbol, nameText string, specifier *Node, dontResolveAlias bool) *Symbol {
+ if symbol.flags&SymbolFlagsModule != 0 {
+ exportSymbol := c.getExportsOfSymbol(symbol)[nameText]
+ resolved := c.resolveSymbolEx(exportSymbol, dontResolveAlias)
+ exportStarDeclaration := c.moduleSymbolLinks.get(symbol).typeOnlyExportStarMap[nameText]
+ c.markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved /*overwriteEmpty*/, false, exportStarDeclaration, nameText)
+ return resolved
+ }
+ return nil
+}
+
+func (c *Checker) isOnlyImportableAsDefault(usage *Node, resolvedModule *Symbol) bool {
+ // In Node.js, JSON modules don't get named exports
+ if ModuleKindNode16 <= c.moduleKind && c.moduleKind <= ModuleKindNodeNext {
+ usageMode := c.getEmitSyntaxForModuleSpecifierExpression(usage)
+ if usageMode == ModuleKindESNext {
+ if resolvedModule == nil {
+ resolvedModule = c.resolveExternalModuleName(usage, usage, true /*ignoreErrors*/)
+ }
+ var targetFile *SourceFile
+ if resolvedModule != nil {
+ targetFile = getSourceFileOfModule(resolvedModule)
+ }
+ return targetFile != nil && (isJsonSourceFile(targetFile) || getDeclarationFileExtension(targetFile.fileName) == ".d.json.ts")
+ }
+ }
+ return false
+}
+
+func (c *Checker) canHaveSyntheticDefault(file *SourceFile, moduleSymbol *Symbol, dontResolveAlias bool, usage *Node) bool {
+ // !!!
+ // var usageMode ResolutionMode
+ // if file != nil {
+ // usageMode = c.getEmitSyntaxForModuleSpecifierExpression(usage)
+ // }
+ // if file != nil && usageMode != ModuleKindNone {
+ // targetMode := host.getImpliedNodeFormatForEmit(file)
+ // if usageMode == ModuleKindESNext && targetMode == ModuleKindCommonJS && ModuleKindNode16 <= c.moduleKind && c.moduleKind <= ModuleKindNodeNext {
+ // // In Node.js, CommonJS modules always have a synthetic default when imported into ESM
+ // return true
+ // }
+ // if usageMode == ModuleKindESNext && targetMode == ModuleKindESNext {
+ // // No matter what the `module` setting is, if we're confident that both files
+ // // are ESM, there cannot be a synthetic default.
+ // return false
+ // }
+ // }
+ if !c.allowSyntheticDefaultImports {
+ return false
+ }
+ // Declaration files (and ambient modules)
+ if file == nil || file.isDeclarationFile {
+ // Definitely cannot have a synthetic default if they have a syntactic default member specified
+ defaultExportSymbol := c.resolveExportByName(moduleSymbol, InternalSymbolNameDefault /*sourceNode*/, nil /*dontResolveAlias*/, true)
+ // Dont resolve alias because we want the immediately exported symbol's declaration
+ if defaultExportSymbol != nil && some(defaultExportSymbol.declarations, isSyntacticDefault) {
+ return false
+ }
+ // It _might_ still be incorrect to assume there is no __esModule marker on the import at runtime, even if there is no `default` member
+ // So we check a bit more,
+ if c.resolveExportByName(moduleSymbol, "__esModule", nil /*sourceNode*/, dontResolveAlias) != nil {
+ // If there is an `__esModule` specified in the declaration (meaning someone explicitly added it or wrote it in their code),
+ // it definitely is a module and does not have a synthetic default
+ return false
+ }
+ // There are _many_ declaration files not written with esmodules in mind that still get compiled into a format with __esModule set
+ // Meaning there may be no default at runtime - however to be on the permissive side, we allow access to a synthetic default member
+ // as there is no marker to indicate if the accompanying JS has `__esModule` or not, or is even native esm
+ return true
+ }
+ // TypeScript files never have a synthetic default (as they are always emitted with an __esModule marker) _unless_ they contain an export= statement
+ return hasExportAssignmentSymbol(moduleSymbol)
+}
+
+func (c *Checker) getEmitSyntaxForModuleSpecifierExpression(usage *Node) ResolutionMode {
+ // !!!
+ // if isStringLiteralLike(usage) {
+ // return host.getEmitSyntaxForUsageLocation(getSourceFileOfNode(usage), usage)
+ // }
+ return ModuleKindNone
+}
+
+func (c *Checker) errorNoModuleMemberSymbol(moduleSymbol *Symbol, targetSymbol *Symbol, node *Node, name *Node) {
+ moduleName := c.getFullyQualifiedName(moduleSymbol, node)
+ declarationName := declarationNameToString(name)
+ var suggestion *Symbol
+ if isIdentifier(name) {
+ suggestion = c.getSuggestedSymbolForNonexistentModule(name, targetSymbol)
+ }
+ if suggestion != nil {
+ suggestionName := c.symbolToString(suggestion)
+ diagnostic := c.error(name, diagnostics.X_0_has_no_exported_member_named_1_Did_you_mean_2, moduleName, declarationName, suggestionName)
+ if suggestion.valueDeclaration != nil {
+ addRelatedInfo(diagnostic, createDiagnosticForNode(suggestion.valueDeclaration, diagnostics.X_0_is_declared_here, suggestionName))
+ }
+ } else {
+ if moduleSymbol.exports[InternalSymbolNameDefault] != nil {
+ c.error(name, diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_to_use_import_1_from_0_instead, moduleName, declarationName)
+
+ } else {
+ c.reportNonExportedMember(node, name, declarationName, moduleSymbol, moduleName)
+ }
+ }
+}
+
+func (c *Checker) reportNonExportedMember(node *Node, name *Node, declarationName string, moduleSymbol *Symbol, moduleName string) {
+ var localSymbol *Symbol
+ if locals := getLocalsOfNode(moduleSymbol.valueDeclaration); locals != nil {
+ localSymbol = locals[getTextOfIdentifierOrLiteral(name)]
+ }
+ exports := moduleSymbol.exports
+ if localSymbol != nil {
+ if exportedEqualsSymbol := exports[InternalSymbolNameExportEquals]; exportedEqualsSymbol != nil {
+ if c.getSymbolIfSameReference(exportedEqualsSymbol, localSymbol) != nil {
+ c.reportInvalidImportEqualsExportMember(node, name, declarationName, moduleName)
+ } else {
+ c.error(name, diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName)
+ }
+ } else {
+ exportedSymbol := findInMap(exports, func(symbol *Symbol) bool {
+ return c.getSymbolIfSameReference(symbol, localSymbol) != nil
+ })
+ var diagnostic *Diagnostic
+ if exportedSymbol != nil {
+ diagnostic = c.error(name, diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, moduleName, declarationName, c.symbolToString(exportedSymbol))
+ } else {
+ diagnostic = c.error(name, diagnostics.Module_0_declares_1_locally_but_it_is_not_exported, moduleName, declarationName)
+ }
+ for i, decl := range localSymbol.declarations {
+ addRelatedInfo(diagnostic, createDiagnosticForNode(decl, ifElse(i == 0, diagnostics.X_0_is_declared_here, diagnostics.X_and_here), declarationName))
+ }
+ }
+ } else {
+ c.error(name, diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName)
+ }
+}
+
+func (c *Checker) reportInvalidImportEqualsExportMember(node *Node, name *Node, declarationName string, moduleName string) {
+ if c.moduleKind >= ModuleKindES2015 {
+ message := ifElse(getESModuleInterop(c.compilerOptions),
+ diagnostics.X_0_can_only_be_imported_by_using_a_default_import,
+ diagnostics.X_0_can_only_be_imported_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import)
+ c.error(name, message, declarationName)
+ } else {
+ message := ifElse(getESModuleInterop(c.compilerOptions),
+ diagnostics.X_0_can_only_be_imported_by_using_import_1_require_2_or_a_default_import,
+ diagnostics.X_0_can_only_be_imported_by_using_import_1_require_2_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import)
+ c.error(name, message, declarationName, declarationName, moduleName)
+ }
+}
+
+func getPropertyNameFromSpecifier(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindImportSpecifier:
+ return node.AsImportSpecifier().propertyName
+ case SyntaxKindExportSpecifier:
+ return node.AsExportSpecifier().propertyName
+ case SyntaxKindBindingElement:
+ return node.AsBindingElement().propertyName
+ }
+ panic("Unhandled case in getSpecifierPropertyName")
+}
+
+func getNameFromSpecifier(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindImportSpecifier:
+ return node.AsImportSpecifier().name
+ case SyntaxKindExportSpecifier:
+ return node.AsExportSpecifier().name
+ case SyntaxKindBindingElement:
+ return node.AsBindingElement().name
+ case SyntaxKindPropertyAccessExpression:
+ return node.AsPropertyAccessExpression().name
+ }
+ panic("Unhandled case in getSpecifierPropertyName")
+}
+
+func (c *Checker) getTargetOfBindingElement(node *Node, dontResolveAlias bool) *Symbol {
+ panic("getTargetOfBindingElement") // !!!
+}
+
+func (c *Checker) getTargetOfExportSpecifier(node *Node, meaning SymbolFlags, dontResolveAlias bool) *Symbol {
+ name := node.AsExportSpecifier().propertyName
+ if name == nil {
+ name = node.AsExportSpecifier().name
+ }
+ if moduleExportNameIsDefault(name) {
+ specifier := c.getModuleSpecifierForImportOrExport(node)
+ if specifier != nil {
+ moduleSymbol := c.resolveExternalModuleName(node, specifier, false /*ignoreErrors*/)
+ if moduleSymbol != nil {
+ return c.getTargetOfModuleDefault(moduleSymbol, node, dontResolveAlias)
+ }
+ }
+ }
+ exportDeclaration := node.parent.parent
+ var resolved *Symbol
+ switch {
+ case exportDeclaration.AsExportDeclaration().moduleSpecifier != nil:
+ resolved = c.getExternalModuleMember(exportDeclaration, node, dontResolveAlias)
+ case isStringLiteral(name):
+ resolved = nil
+ default:
+ resolved = c.resolveEntityName(name, meaning, false /*ignoreErrors*/, dontResolveAlias, nil /*location*/)
+ }
+ c.markSymbolOfAliasDeclarationIfTypeOnly(node, nil /*immediateTarget*/, resolved, false /*overwriteEmpty*/, nil, "")
+ return resolved
+}
+
+func (c *Checker) getTargetOfExportAssignment(node *Node, dontResolveAlias bool) *Symbol {
+ resolved := c.getTargetOfAliasLikeExpression(node.AsExportAssignment().expression, dontResolveAlias)
+ c.markSymbolOfAliasDeclarationIfTypeOnly(node, nil /*immediateTarget*/, resolved, false /*overwriteEmpty*/, nil, "")
+ return resolved
+}
+
+func (c *Checker) getTargetOfBinaryExpression(node *Node, dontResolveAlias bool) *Symbol {
+ resolved := c.getTargetOfAliasLikeExpression(node.AsBinaryExpression().right, dontResolveAlias)
+ c.markSymbolOfAliasDeclarationIfTypeOnly(node, nil /*immediateTarget*/, resolved, false /*overwriteEmpty*/, nil, "")
+ return resolved
+}
+
+func (c *Checker) getTargetOfAliasLikeExpression(expression *Node, dontResolveAlias bool) *Symbol {
+ if isClassExpression(expression) {
+ return c.unknownSymbol
+ // !!! return c.checkExpressionCached(expression).symbol
+ }
+ if !isEntityName(expression) && !isEntityNameExpression(expression) {
+ return nil
+ }
+ aliasLike := c.resolveEntityName(expression, SymbolFlagsValue|SymbolFlagsType|SymbolFlagsNamespace, true /*ignoreErrors*/, dontResolveAlias, nil /*location*/)
+ if aliasLike != nil {
+ return aliasLike
+ }
+ return c.unknownSymbol
+ // !!! c.checkExpressionCached(expression)
+ // return c.getNodeLinks(expression).resolvedSymbol
+}
+
+func (c *Checker) getTargetOfNamespaceExportDeclaration(node *Node, dontResolveAlias bool) *Symbol {
+ if canHaveSymbol(node.parent) {
+ resolved := c.resolveExternalModuleSymbol(node.parent.Symbol(), dontResolveAlias)
+ c.markSymbolOfAliasDeclarationIfTypeOnly(node, nil /*immediateTarget*/, resolved, false /*overwriteEmpty*/, nil, "")
+ return resolved
+ }
+ return nil
+}
+
+func (c *Checker) getTargetOfAccessExpression(node *Node, dontRecursivelyResolve bool) *Symbol {
+ if isBinaryExpression(node.parent) {
+ expr := node.parent.AsBinaryExpression()
+ if expr.left == node && expr.operatorToken.kind == SyntaxKindEqualsToken {
+ return c.getTargetOfAliasLikeExpression(expr.right, dontRecursivelyResolve)
+ }
+ }
+ return nil
+}
+
+func (c *Checker) getModuleSpecifierForImportOrExport(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindImportClause:
+ return getModuleSpecifierFromNode(node.parent)
+ case SyntaxKindImportEqualsDeclaration:
+ if isExternalModuleReference(node.AsImportEqualsDeclaration().moduleReference) {
+ return node.AsImportEqualsDeclaration().moduleReference.AsExternalModuleReference().expression
+ } else {
+ return nil
+ }
+ case SyntaxKindNamespaceImport:
+ return getModuleSpecifierFromNode(node.parent.parent)
+ case SyntaxKindImportSpecifier:
+ return getModuleSpecifierFromNode(node.parent.parent.parent)
+ case SyntaxKindNamespaceExport:
+ return getModuleSpecifierFromNode(node.parent)
+ case SyntaxKindExportSpecifier:
+ return getModuleSpecifierFromNode(node.parent.parent)
+ }
+ panic("Unhandled case in getModuleSpecifierForImportOrExport")
+}
+
+func getModuleSpecifierFromNode(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindImportDeclaration:
+ return node.AsImportDeclaration().moduleSpecifier
+ case SyntaxKindExportDeclaration:
+ return node.AsExportDeclaration().moduleSpecifier
+ }
+ panic("Unhandled case in getModuleSpecifierFromNode")
+}
+
+/**
+ * Marks a symbol as type-only if its declaration is syntactically type-only.
+ * If it is not itself marked type-only, but resolves to a type-only alias
+ * somewhere in its resolution chain, save a reference to the type-only alias declaration
+ * so the alias _not_ marked type-only can be identified as _transitively_ type-only.
+ *
+ * This function is called on each alias declaration that could be type-only or resolve to
+ * another type-only alias during `resolveAlias`, so that later, when an alias is used in a
+ * JS-emitting expression, we can quickly determine if that symbol is effectively type-only
+ * and issue an error if so.
+ *
+ * @param aliasDeclaration The alias declaration not marked as type-only
+ * @param immediateTarget The symbol to which the alias declaration immediately resolves
+ * @param finalTarget The symbol to which the alias declaration ultimately resolves
+ * @param overwriteEmpty Checks `resolvesToSymbol` for type-only declarations even if `aliasDeclaration`
+ * has already been marked as not resolving to a type-only alias. Used when recursively resolving qualified
+ * names of import aliases, e.g. `import C = a.b.C`. If namespace `a` is not found to be type-only, the
+ * import declaration will initially be marked as not resolving to a type-only symbol. But, namespace `b`
+ * must still be checked for a type-only marker, overwriting the previous negative result if found.
+ */
+
+func (c *Checker) markSymbolOfAliasDeclarationIfTypeOnly(aliasDeclaration *Node, immediateTarget *Symbol, finalTarget *Symbol, overwriteEmpty bool, exportStarDeclaration *Node, exportStarName string) bool {
+ if aliasDeclaration == nil || isPropertyAccessExpression(aliasDeclaration) {
+ return false
+ }
+ // If the declaration itself is type-only, mark it and return. No need to check what it resolves to.
+ sourceSymbol := c.getSymbolOfDeclaration(aliasDeclaration)
+ if isTypeOnlyImportOrExportDeclaration(aliasDeclaration) {
+ links := c.aliasSymbolLinks.get(sourceSymbol)
+ links.typeOnlyDeclaration = aliasDeclaration
+ return true
+ }
+ if exportStarDeclaration != nil {
+ links := c.aliasSymbolLinks.get(sourceSymbol)
+ links.typeOnlyDeclaration = exportStarDeclaration
+ if sourceSymbol.name != exportStarName {
+ links.typeOnlyExportStarName = exportStarName
+ }
+ return true
+ }
+ links := c.aliasSymbolLinks.get(sourceSymbol)
+ return c.markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, immediateTarget, overwriteEmpty) || c.markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, finalTarget, overwriteEmpty)
+}
+
+func (c *Checker) markSymbolOfAliasDeclarationIfTypeOnlyWorker(aliasDeclarationLinks *AliasSymbolLinks, target *Symbol, overwriteEmpty bool) bool {
+ if target != nil && (aliasDeclarationLinks.typeOnlyDeclaration == nil || overwriteEmpty && aliasDeclarationLinks.typeOnlyDeclarationResolved && aliasDeclarationLinks.typeOnlyDeclaration == nil) {
+ exportSymbol := target.exports[InternalSymbolNameExportEquals]
+ if exportSymbol == nil {
+ exportSymbol = target
+ }
+ typeOnly := some(exportSymbol.declarations, isTypeOnlyImportOrExportDeclaration)
+ aliasDeclarationLinks.typeOnlyDeclarationResolved = true
+ aliasDeclarationLinks.typeOnlyDeclaration = nil
+ if typeOnly {
+ aliasDeclarationLinks.typeOnlyDeclaration = c.aliasSymbolLinks.get(exportSymbol).typeOnlyDeclaration
+ }
+ }
+ return aliasDeclarationLinks.typeOnlyDeclaration != nil
+}
+
+func (c *Checker) resolveExternalModuleName(location *Node, moduleReferenceExpression *Node, ignoreErrors bool) *Symbol {
+ isClassic := getEmitModuleResolutionKind(c.compilerOptions) == ModuleResolutionKindClassic
+ errorMessage := ifElse(isClassic,
+ diagnostics.Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_nodenext_or_to_add_aliases_to_the_paths_option,
+ diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations)
+ return c.resolveExternalModuleNameWorker(location, moduleReferenceExpression, ifElse(ignoreErrors, nil, errorMessage), ignoreErrors, false /*isForAugmentation*/)
+}
+
+func (c *Checker) resolveExternalModuleNameWorker(location *Node, moduleReferenceExpression *Node, moduleNotFoundError *diagnostics.Message, ignoreErrors bool, isForAugmentation bool) *Symbol {
+ if isStringLiteralLike(moduleReferenceExpression) {
+ return c.resolveExternalModule(location, getTextOfIdentifierOrLiteral(moduleReferenceExpression), moduleNotFoundError, ifElse(!ignoreErrors, moduleReferenceExpression, nil), isForAugmentation)
+ }
+ return nil
+}
+
+func (c *Checker) resolveExternalModule(location *Node, moduleReference string, moduleNotFoundError *diagnostics.Message, errorNode *Node, isForAugmentation bool) *Symbol {
+ if errorNode != nil && strings.HasPrefix(moduleReference, "@types/") {
+ withoutAtTypePrefix := moduleReference[len("@types/"):]
+ c.error(errorNode, diagnostics.Cannot_import_type_declaration_files_Consider_importing_0_instead_of_1, withoutAtTypePrefix, moduleReference)
+ }
+ ambientModule := c.tryFindAmbientModule(moduleReference, true /*withAugmentations*/)
+ if ambientModule != nil {
+ return ambientModule
+ }
+ // !!! The following only implements simple module resoltion
+ sourceFile := c.program.getResolvedModule(getSourceFileOfNode(location), moduleReference)
+ if sourceFile != nil {
+ if sourceFile.symbol != nil {
+ return c.getMergedSymbol(sourceFile.symbol)
+ }
+ if errorNode != nil && moduleNotFoundError != nil && !isSideEffectImport(errorNode) {
+ c.error(errorNode, diagnostics.File_0_is_not_a_module, sourceFile.fileName)
+ }
+ return nil
+ }
+ if errorNode != nil && moduleNotFoundError != nil {
+ c.error(errorNode, moduleNotFoundError, moduleReference)
+ }
+ return nil
+}
+
+func (c *Checker) tryFindAmbientModule(moduleName string, withAugmentations bool) *Symbol {
+ if isExternalModuleNameRelative(moduleName) {
+ return nil
+ }
+ symbol := c.getSymbol(c.globals, "\""+moduleName+"\"", SymbolFlagsValueModule)
+ // merged symbol is module declaration symbol combined with all augmentations
+ if withAugmentations {
+ return c.getMergedSymbol(symbol)
+ }
+ return symbol
+}
+
+func (c *Checker) resolveExternalModuleSymbol(moduleSymbol *Symbol, dontResolveAlias bool) *Symbol {
+ if moduleSymbol != nil {
+ exportEquals := c.resolveSymbolEx(moduleSymbol.exports[InternalSymbolNameExportEquals], dontResolveAlias)
+ exported := c.getMergedSymbol(c.getCommonJsExportEquals(c.getMergedSymbol(exportEquals), c.getMergedSymbol(moduleSymbol)))
+ if exported != nil {
+ return exported
+ }
+ }
+ return moduleSymbol
+}
+
+func (c *Checker) getCommonJsExportEquals(exported *Symbol, moduleSymbol *Symbol) *Symbol {
+ if exported == nil || exported == c.unknownSymbol || exported == moduleSymbol || len(moduleSymbol.exports) == 1 || exported.flags&SymbolFlagsAlias != 0 {
+ return exported
+ }
+ links := c.moduleSymbolLinks.get(exported)
+ if links.cjsExportMerged != nil {
+ return links.cjsExportMerged
+ }
+ var merged *Symbol
+ if exported.flags&SymbolFlagsTransient != 0 {
+ merged = exported
+ } else {
+ merged = c.cloneSymbol(exported)
+ }
+ merged.flags |= SymbolFlagsValueModule
+ mergedExports := getExports(merged)
+ for name, s := range moduleSymbol.exports {
+ if name != InternalSymbolNameExportEquals {
+ if existing, ok := mergedExports[name]; ok {
+ s = c.mergeSymbol(existing, s /*unidirectional*/, false)
+ }
+ mergedExports[name] = s
+ }
+ }
+ if merged == exported {
+ // We just mutated a symbol, reset any cached links we may have already set
+ // (Notably required to make late bound members appear)
+ c.moduleSymbolLinks.get(merged).resolvedExports = nil
+ // !!! c.moduleSymbolLinks.get(merged).resolvedMembers = nil
+ }
+ c.moduleSymbolLinks.get(merged).cjsExportMerged = merged
+ links.cjsExportMerged = merged
+ return links.cjsExportMerged
+}
+
+// An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export ='
+// references a symbol that is at least declared as a module or a variable. The target of the 'export =' may
+// combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable).
+func (c *Checker) resolveESModuleSymbol(moduleSymbol *Symbol, referencingLocation *Node, dontResolveAlias bool, suppressInteropError bool) *Symbol {
+ symbol := c.resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias)
+ if !dontResolveAlias && symbol != nil {
+ if !suppressInteropError && symbol.flags&(SymbolFlagsModule|SymbolFlagsVariable) == 0 && getDeclarationOfKind(symbol, SyntaxKindSourceFile) == nil {
+ compilerOptionName := ifElse(c.moduleKind >= ModuleKindES2015, "allowSyntheticDefaultImports", "esModuleInterop")
+ c.error(referencingLocation, diagnostics.This_module_can_only_be_referenced_with_ECMAScript_imports_Slashexports_by_turning_on_the_0_flag_and_referencing_its_default_export, compilerOptionName)
+ return symbol
+ }
+ referenceParent := referencingLocation.parent
+ if isImportDeclaration(referenceParent) && getNamespaceDeclarationNode(referenceParent) != nil || isImportCall(referenceParent) {
+ var reference *Node
+ if isImportCall(referenceParent) {
+ reference = referenceParent.AsCallExpression().arguments[0]
+ } else {
+ reference = referenceParent.AsImportDeclaration().moduleSpecifier
+ }
+ typ := c.getTypeOfSymbol(symbol)
+ defaultOnlyType := c.getTypeWithSyntheticDefaultOnly(typ, symbol, moduleSymbol, reference)
+ if defaultOnlyType != nil {
+ return c.cloneTypeAsModuleType(symbol, defaultOnlyType, referenceParent)
+ }
+ // !!!
+ // targetFile := moduleSymbol. /* ? */ declarations. /* ? */ find(isSourceFile)
+ // isEsmCjsRef := targetFile && c.isESMFormatImportImportingCommonjsFormatFile(c.getEmitSyntaxForModuleSpecifierExpression(reference), host.getImpliedNodeFormatForEmit(targetFile))
+ // if getESModuleInterop(c.compilerOptions) || isEsmCjsRef {
+ // sigs := c.getSignaturesOfStructuredType(type_, SignatureKindCall)
+ // if !sigs || !sigs.length {
+ // sigs = c.getSignaturesOfStructuredType(type_, SignatureKindConstruct)
+ // }
+ // if (sigs && sigs.length) || c.getPropertyOfType(type_, InternalSymbolNameDefault /*skipObjectFunctionPropertyAugment*/, true) || isEsmCjsRef {
+ // var moduleType *Type
+ // if type_.flags & TypeFlagsStructuredType {
+ // moduleType = c.getTypeWithSyntheticDefaultImportType(type_, symbol, moduleSymbol, reference)
+ // } else {
+ // moduleType = c.createDefaultPropertyWrapperForModule(symbol, symbol.parent)
+ // }
+ // return c.cloneTypeAsModuleType(symbol, moduleType, referenceParent)
+ // }
+ // }
+ }
+ }
+ return symbol
+}
+
+func (c *Checker) getTypeWithSyntheticDefaultOnly(typ *Type, symbol *Symbol, originalSymbol *Symbol, moduleSpecifier *Node) *Type {
+ return nil // !!!
+}
+
+func (c *Checker) cloneTypeAsModuleType(symbol *Symbol, moduleType *Type, referenceParent *Node) *Symbol {
+ result := c.newSymbol(symbol.flags, symbol.name)
+ result.constEnumOnlyModule = symbol.constEnumOnlyModule
+ result.declarations = slices.Clone(symbol.declarations)
+ result.valueDeclaration = symbol.valueDeclaration
+ result.members = maps.Clone(symbol.members)
+ result.exports = maps.Clone(symbol.exports)
+ result.parent = symbol.parent
+ links := c.exportTypeLinks.get(result)
+ links.target = symbol
+ links.originatingImport = referenceParent
+ resolvedModuleType := c.resolveStructuredTypeMembers(moduleType)
+ c.valueSymbolLinks.get(result).resolvedType = c.newAnonymousType(result, resolvedModuleType.members, nil, nil, resolvedModuleType.indexInfos)
+ return result
+}
+
+func (c *Checker) getTargetOfAliasDeclaration(node *Node, dontRecursivelyResolve bool /* = false */) *Symbol {
+ switch node.kind {
+ case SyntaxKindImportEqualsDeclaration, SyntaxKindVariableDeclaration:
+ return c.getTargetOfImportEqualsDeclaration(node, dontRecursivelyResolve)
+ case SyntaxKindImportClause:
+ return c.getTargetOfImportClause(node, dontRecursivelyResolve)
+ case SyntaxKindNamespaceImport:
+ return c.getTargetOfNamespaceImport(node, dontRecursivelyResolve)
+ case SyntaxKindNamespaceExport:
+ return c.getTargetOfNamespaceExport(node, dontRecursivelyResolve)
+ case SyntaxKindImportSpecifier:
+ return c.getTargetOfImportSpecifier(node, dontRecursivelyResolve)
+ case SyntaxKindBindingElement:
+ return c.getTargetOfBindingElement(node, dontRecursivelyResolve)
+ case SyntaxKindExportSpecifier:
+ return c.getTargetOfExportSpecifier(node, SymbolFlagsValue|SymbolFlagsType|SymbolFlagsNamespace, dontRecursivelyResolve)
+ case SyntaxKindExportAssignment:
+ return c.getTargetOfExportAssignment(node, dontRecursivelyResolve)
+ case SyntaxKindBinaryExpression:
+ return c.getTargetOfBinaryExpression(node, dontRecursivelyResolve)
+ case SyntaxKindNamespaceExportDeclaration:
+ return c.getTargetOfNamespaceExportDeclaration(node, dontRecursivelyResolve)
+ case SyntaxKindShorthandPropertyAssignment:
+ return c.resolveEntityName(node.AsShorthandPropertyAssignment().name, SymbolFlagsValue|SymbolFlagsType|SymbolFlagsNamespace, true /*ignoreErrors*/, dontRecursivelyResolve, nil /*location*/)
+ case SyntaxKindPropertyAssignment:
+ return c.getTargetOfAliasLikeExpression(node.AsPropertyAssignment().initializer, dontRecursivelyResolve)
+ case SyntaxKindElementAccessExpression, SyntaxKindPropertyAccessExpression:
+ return c.getTargetOfAccessExpression(node, dontRecursivelyResolve)
+ }
+ panic("Unhandled case in getTargetOfAliasDeclaration")
+}
+
+/**
+ * Resolves a qualified name and any involved aliases.
+ */
+func (c *Checker) resolveEntityName(name *Node, meaning SymbolFlags, ignoreErrors bool, dontResolveAlias bool, location *Node) *Symbol {
+ if nodeIsMissing(name) {
+ return nil
+ }
+ var symbol *Symbol
+ switch name.kind {
+ case SyntaxKindIdentifier:
+ var message *diagnostics.Message
+ if !ignoreErrors {
+ if meaning == SymbolFlagsNamespace || nodeIsSynthesized(name) {
+ message = diagnostics.Cannot_find_namespace_0
+ } else {
+ message = c.getCannotFindNameDiagnosticForName(getFirstIdentifier(name))
+ }
+ }
+ resolveLocation := location
+ if resolveLocation == nil {
+ resolveLocation = name
+ }
+ symbol = c.getMergedSymbol(c.resolveName(resolveLocation, name.AsIdentifier().text, meaning, message, true /*isUse*/, false /*excludeGlobals*/))
+ case SyntaxKindQualifiedName:
+ qualified := name.AsQualifiedName()
+ symbol = c.resolveQualifiedName(name, qualified.left, qualified.right, meaning, ignoreErrors, dontResolveAlias, location)
+ case SyntaxKindPropertyAccessExpression:
+ access := name.AsPropertyAccessExpression()
+ symbol = c.resolveQualifiedName(name, access.expression, access.name, meaning, ignoreErrors, dontResolveAlias, location)
+ default:
+ panic("Unknown entity name kind")
+ }
+ if symbol != nil {
+ if !nodeIsSynthesized(name) && isEntityName(name) && (symbol.flags&SymbolFlagsAlias != 0 || name.parent.kind == SyntaxKindExportAssignment) {
+ c.markSymbolOfAliasDeclarationIfTypeOnly(getAliasDeclarationFromName(name), symbol, nil /*finalTarget*/, true /*overwriteEmpty*/, nil, "")
+ }
+ if symbol.flags&meaning == 0 && !dontResolveAlias {
+ return c.resolveAlias(symbol)
+ }
+ }
+ return symbol
+}
+
+func (c *Checker) resolveQualifiedName(name *Node, left *Node, right *Node, meaning SymbolFlags, ignoreErrors bool, dontResolveAlias bool, location *Node) *Symbol {
+ namespace := c.resolveEntityName(left, SymbolFlagsNamespace, ignoreErrors /*dontResolveAlias*/, false, location)
+ if namespace == nil || nodeIsMissing(right) {
+ return nil
+ }
+ if namespace == c.unknownSymbol {
+ return namespace
+ }
+ text := right.AsIdentifier().text
+ symbol := c.getMergedSymbol(c.getSymbol(c.getExportsOfSymbol(namespace), text, meaning))
+ if symbol != nil && namespace.flags&SymbolFlagsAlias != 0 {
+ // `namespace` can be resolved further if there was a symbol merge with a re-export
+ symbol = c.getMergedSymbol(c.getSymbol(c.getExportsOfSymbol(c.resolveAlias(namespace)), text, meaning))
+ }
+ if symbol == nil {
+ if !ignoreErrors {
+ namespaceName := c.getFullyQualifiedName(namespace, nil /*containingLocation*/)
+ declarationName := declarationNameToString(right)
+ suggestionForNonexistentModule := c.getSuggestedSymbolForNonexistentModule(right, namespace)
+ if suggestionForNonexistentModule != nil {
+ c.error(right, diagnostics.X_0_has_no_exported_member_named_1_Did_you_mean_2, namespaceName, declarationName, c.symbolToString(suggestionForNonexistentModule))
+ return nil
+ }
+ var containingQualifiedName *Node
+ if isQualifiedName(name) {
+ containingQualifiedName = getContainingQualifiedNameNode(name)
+ }
+ canSuggestTypeof := c.globalObjectType != nil && meaning&SymbolFlagsType != 0 && containingQualifiedName != nil && !isTypeOfExpression(containingQualifiedName.parent) && c.tryGetQualifiedNameAsValue(containingQualifiedName) != nil
+ if canSuggestTypeof {
+ c.error(containingQualifiedName, diagnostics.X_0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, entityNameToString(containingQualifiedName))
+ return nil
+ }
+ if meaning&SymbolFlagsNamespace != 0 {
+ if isQualifiedName(name.parent) {
+ exportedTypeSymbol := c.getMergedSymbol(c.getSymbol(c.getExportsOfSymbol(namespace), text, SymbolFlagsType))
+ if exportedTypeSymbol != nil {
+ qualified := name.parent.AsQualifiedName()
+ c.error(qualified.right, diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, c.symbolToString(exportedTypeSymbol), qualified.right.AsIdentifier().text)
+ return nil
+ }
+ }
+ }
+ c.error(right, diagnostics.Namespace_0_has_no_exported_member_1, namespaceName, declarationName)
+ }
+ }
+ return symbol
+}
+
+func (c *Checker) tryGetQualifiedNameAsValue(node *Node) *Symbol {
+ id := getFirstIdentifier(node)
+ symbol := c.resolveName(id, id.AsIdentifier().text, SymbolFlagsValue, nil /*nameNotFoundMessage*/, true /*isUse*/, false /*excludeGlobals*/)
+ if symbol == nil {
+ return nil
+ }
+ n := id
+ for isQualifiedName(n.parent) {
+ t := c.getTypeOfSymbol(symbol)
+ symbol = c.getPropertyOfType(t, n.parent.AsQualifiedName().right.AsIdentifier().text)
+ if symbol == nil {
+ return nil
+ }
+ n = n.parent
+ }
+ return symbol
+}
+
+func (c *Checker) getSuggestedSymbolForNonexistentModule(name *Node, targetModule *Symbol) *Symbol {
+ return nil // !!!
+}
+
+func (c *Checker) getFullyQualifiedName(symbol *Symbol, containingLocation *Node) string {
+ if symbol.parent != nil {
+ return c.getFullyQualifiedName(symbol.parent, containingLocation) + "." + c.symbolToString(symbol)
+ }
+ return c.symbolToString(symbol) // !!!
+}
+
+func (c *Checker) getExportsOfSymbol(symbol *Symbol) SymbolTable {
+ if symbol.flags&SymbolFlagsLateBindingContainer != 0 {
+ return c.getResolvedMembersOrExportsOfSymbol(symbol, MembersOrExportsResolutionKindResolvedExports)
+ }
+ if symbol.flags&SymbolFlagsModule != 0 {
+ return c.getExportsOfModule(symbol)
+ }
+ return symbol.exports
+}
+
+func (c *Checker) getResolvedMembersOrExportsOfSymbol(symbol *Symbol, resolutionKind MembersOrExportsResolutionKind) SymbolTable {
+ links := c.membersAndExportsLinks.get(symbol)
+ if links[resolutionKind] == nil {
+ isStatic := resolutionKind == MembersOrExportsResolutionKindResolvedExports
+ earlySymbols := symbol.exports
+ switch {
+ case !isStatic:
+ earlySymbols = symbol.members
+ case symbol.flags&SymbolFlagsModule != 0:
+ earlySymbols, _ = c.getExportsOfModuleWorker(symbol)
+ }
+ links[resolutionKind] = earlySymbols
+ // !!! Resolve late-bound members
+ }
+ return links[resolutionKind]
+}
+
+/**
+ * Gets a SymbolTable containing both the early- and late-bound members of a symbol.
+ *
+ * For a description of late-binding, see `lateBindMember`.
+ */
+func (c *Checker) getMembersOfSymbol(symbol *Symbol) SymbolTable {
+ if symbol.flags&SymbolFlagsLateBindingContainer != 0 {
+ return c.getResolvedMembersOrExportsOfSymbol(symbol, MembersOrExportsResolutionKindresolvedMembers)
+ }
+ return symbol.members
+}
+
+func (c *Checker) getExportsOfModule(moduleSymbol *Symbol) SymbolTable {
+ links := c.moduleSymbolLinks.get(moduleSymbol)
+ if links.resolvedExports == nil {
+ exports, typeOnlyExportStarMap := c.getExportsOfModuleWorker(moduleSymbol)
+ links.resolvedExports = exports
+ links.typeOnlyExportStarMap = typeOnlyExportStarMap
+ }
+ return links.resolvedExports
+}
+
+type ExportCollision struct {
+ specifierText string
+ exportsWithDuplicate []*Node
+}
+
+type ExportCollisionTable = map[string]*ExportCollision
+
+func (c *Checker) getExportsOfModuleWorker(moduleSymbol *Symbol) (exports SymbolTable, typeOnlyExportStarMap map[string]*Node) {
+ var visitedSymbols []*Symbol
+ nonTypeOnlyNames := make(map[string]bool)
+ // The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example,
+ // module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error.
+ var visit func(*Symbol, *Node, bool) SymbolTable
+ visit = func(symbol *Symbol, exportStar *Node, isTypeOnly bool) SymbolTable {
+ if !isTypeOnly && symbol != nil {
+ // Add non-type-only names before checking if we've visited this module,
+ // because we might have visited it via an 'export type *', and visiting
+ // again with 'export *' will override the type-onlyness of its exports.
+ for name := range symbol.exports {
+ nonTypeOnlyNames[name] = true
+ }
+ }
+ if symbol == nil || symbol.exports == nil || slices.Contains(visitedSymbols, symbol) {
+ return nil
+ }
+ symbols := maps.Clone(symbol.exports)
+ // All export * declarations are collected in an __export symbol by the binder
+ exportStars := symbol.exports[InternalSymbolNameExportStar]
+ if exportStars != nil {
+ nestedSymbols := make(SymbolTable)
+ lookupTable := make(ExportCollisionTable)
+ for _, node := range exportStars.declarations {
+ resolvedModule := c.resolveExternalModuleName(node, node.AsExportDeclaration().moduleSpecifier, false /*ignoreErrors*/)
+ exportedSymbols := visit(resolvedModule, node, isTypeOnly || node.AsExportDeclaration().isTypeOnly)
+ c.extendExportSymbols(nestedSymbols, exportedSymbols, lookupTable, node)
+ }
+ for id, s := range lookupTable {
+ // It's not an error if the file with multiple `export *`s with duplicate names exports a member with that name itself
+ if id == "export=" || len(s.exportsWithDuplicate) == 0 || symbols[id] != nil {
+ continue
+ }
+ for _, node := range s.exportsWithDuplicate {
+ c.diagnostics.add(createDiagnosticForNode(node, diagnostics.Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, s.specifierText, id))
+ }
+ }
+ c.extendExportSymbols(symbols, nestedSymbols, nil, nil)
+ }
+ if exportStar != nil && exportStar.AsExportDeclaration().isTypeOnly {
+ if typeOnlyExportStarMap == nil {
+ typeOnlyExportStarMap = make(map[string]*Node)
+ }
+ for name := range symbols {
+ typeOnlyExportStarMap[name] = exportStar
+ }
+ }
+ return symbols
+ }
+ // A module defined by an 'export=' consists of one export that needs to be resolved
+ moduleSymbol = c.resolveExternalModuleSymbol(moduleSymbol, false /*dontResolveAlias*/)
+ exports = visit(moduleSymbol, nil, false)
+ if exports == nil {
+ exports = make(SymbolTable)
+ }
+ for name := range nonTypeOnlyNames {
+ delete(typeOnlyExportStarMap, name)
+ }
+ return
+}
+
+/**
+ * Extends one symbol table with another while collecting information on name collisions for error message generation into the `lookupTable` argument
+ * Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables
+ */
+func (c *Checker) extendExportSymbols(target SymbolTable, source SymbolTable, lookupTable ExportCollisionTable, exportNode *Node) {
+ for id, sourceSymbol := range source {
+ if id == InternalSymbolNameDefault {
+ continue
+ }
+ targetSymbol := target[id]
+ if targetSymbol == nil {
+ target[id] = sourceSymbol
+ if lookupTable != nil && exportNode != nil {
+ lookupTable[id] = &ExportCollision{
+ specifierText: getTextOfNode(exportNode.AsExportDeclaration().moduleSpecifier),
+ }
+ }
+ } else if lookupTable != nil && exportNode != nil && c.resolveSymbol(targetSymbol) != c.resolveSymbol(sourceSymbol) {
+ s := lookupTable[id]
+ s.exportsWithDuplicate = append(s.exportsWithDuplicate, exportNode)
+ }
+ }
+}
+
+/**
+ * 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
+}
+
+func (c *Checker) resolveAlias(symbol *Symbol) *Symbol {
+ if symbol == c.unknownSymbol {
+ return symbol // !!! Remove once all symbols are properly resolved
+ }
+ if symbol.flags&SymbolFlagsAlias == 0 {
+ panic("Should only get alias here")
+ }
+ links := c.aliasSymbolLinks.get(symbol)
+ if links.aliasTarget == nil {
+ links.aliasTarget = c.resolvingSymbol
+ node := c.getDeclarationOfAliasSymbol(symbol)
+ if node == nil {
+ panic("Unexpected nil in resolveAlias")
+ }
+ target := c.getTargetOfAliasDeclaration(node, false /*dontRecursivelyResolve*/)
+ if links.aliasTarget == c.resolvingSymbol {
+ if target == nil {
+ target = c.unknownSymbol
+ }
+ links.aliasTarget = target
+ } else {
+ c.error(node, diagnostics.Circular_definition_of_import_alias_0, c.symbolToString(symbol))
+ }
+ } else if links.aliasTarget == c.resolvingSymbol {
+ links.aliasTarget = c.unknownSymbol
+ }
+ return links.aliasTarget
+}
+
+/**
+ * Gets combined flags of a `symbol` and all alias targets it resolves to. `resolveAlias`
+ * is typically recursive over chains of aliases, but stops mid-chain if an alias is merged
+ * with another exported symbol, e.g.
+ * ```ts
+ * // a.ts
+ * export const a = 0;
+ * // b.ts
+ * export { a } from "./a";
+ * export type a = number;
+ * // c.ts
+ * import { a } from "./b";
+ * ```
+ * Calling `resolveAlias` on the `a` in c.ts would stop at the merged symbol exported
+ * from b.ts, even though there is still more alias to resolve. Consequently, if we were
+ * trying to determine if the `a` in c.ts has a value meaning, looking at the flags on
+ * the local symbol and on the symbol returned by `resolveAlias` is not enough.
+ * @returns SymbolFlags.All if `symbol` is an alias that ultimately resolves to `unknown`;
+ * combined flags of all alias targets otherwise.
+ */
+func (c *Checker) getSymbolFlags(symbol *Symbol) SymbolFlags {
+ return c.getSymbolFlagsEx(symbol, false /*excludeTypeOnlyMeanings*/, false /*excludeLocalMeanings*/)
+}
+
+func (c *Checker) getSymbolFlagsEx(symbol *Symbol, excludeTypeOnlyMeanings bool, excludeLocalMeanings bool) SymbolFlags {
+ var typeOnlyDeclaration *Node
+ if excludeTypeOnlyMeanings {
+ typeOnlyDeclaration = c.getTypeOnlyAliasDeclaration(symbol)
+ }
+ typeOnlyDeclarationIsExportStar := typeOnlyDeclaration != nil && isExportDeclaration(typeOnlyDeclaration)
+ var typeOnlyResolution *Symbol
+ if typeOnlyDeclaration != nil {
+ if typeOnlyDeclarationIsExportStar {
+ moduleSpecifier := typeOnlyDeclaration.AsExportDeclaration().moduleSpecifier
+ typeOnlyResolution = c.resolveExternalModuleName(moduleSpecifier, moduleSpecifier /*ignoreErrors*/, true)
+ } else {
+ typeOnlyResolution = c.resolveAlias(typeOnlyDeclaration.Symbol())
+ }
+ }
+ var typeOnlyExportStarTargets SymbolTable
+ if typeOnlyDeclarationIsExportStar && typeOnlyResolution != nil {
+ typeOnlyExportStarTargets = c.getExportsOfModule(typeOnlyResolution)
+ }
+ var flags SymbolFlags
+ if !excludeLocalMeanings {
+ flags = symbol.flags
+ }
+ var seenSymbols map[*Symbol]bool
+ for symbol.flags&SymbolFlagsAlias != 0 {
+ target := c.getExportSymbolOfValueSymbolIfExported(c.resolveAlias(symbol))
+ if !typeOnlyDeclarationIsExportStar && target == typeOnlyResolution || typeOnlyExportStarTargets[target.name] == target {
+ break
+ }
+ if target == c.unknownSymbol {
+ return SymbolFlagsAll
+ }
+ // Optimizations - try to avoid creating or adding to
+ // `seenSymbols` if possible
+ if target == symbol || seenSymbols[target] {
+ break
+ }
+ if target.flags&SymbolFlagsAlias != 0 {
+ if seenSymbols == nil {
+ seenSymbols = make(map[*Symbol]bool)
+ seenSymbols[symbol] = true
+ }
+ seenSymbols[target] = true
+ }
+ flags |= target.flags
+ symbol = target
+ }
+ return flags
+}
+
+func (c *Checker) getDeclarationOfAliasSymbol(symbol *Symbol) *Node {
+ return findLast(symbol.declarations, c.isAliasSymbolDeclaration)
+}
+
+/**
+ * An alias symbol is created by one of the following declarations:
+ * import = ...
+ * import from ...
+ * import * as from ...
+ * import { x as } from ...
+ * export { x as } from ...
+ * export * as ns from ...
+ * export =
+ * export default
+ */
+func (c *Checker) isAliasSymbolDeclaration(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindImportEqualsDeclaration, SyntaxKindNamespaceExportDeclaration, SyntaxKindNamespaceImport, SyntaxKindNamespaceExport,
+ SyntaxKindImportSpecifier, SyntaxKindExportSpecifier:
+ return true
+ case SyntaxKindImportClause:
+ return node.AsImportClause().name != nil
+ case SyntaxKindExportAssignment:
+ return exportAssignmentIsAlias(node)
+ }
+ return false
+}
+
+func (c *Checker) getTypeOfSymbol(symbol *Symbol) *Type {
+ // !!!
+ // checkFlags := symbol.checkFlags
+ // if checkFlags&CheckFlagsDeferredType != 0 {
+ // return c.getTypeOfSymbolWithDeferredType(symbol)
+ // }
+ // if checkFlags&CheckFlagsInstantiated != 0 {
+ // return c.getTypeOfInstantiatedSymbol(symbol)
+ // }
+ // if checkFlags&CheckFlagsMapped != 0 {
+ // return c.getTypeOfMappedSymbol(symbol.(MappedSymbol))
+ // }
+ // if checkFlags&CheckFlagsReverseMapped != 0 {
+ // return c.getTypeOfReverseMappedSymbol(symbol.(ReverseMappedSymbol))
+ // }
+ if symbol.flags&(SymbolFlagsVariable|SymbolFlagsProperty) != 0 {
+ return c.getTypeOfVariableOrParameterOrProperty(symbol)
+ }
+ if symbol.flags&(SymbolFlagsFunction|SymbolFlagsMethod|SymbolFlagsClass|SymbolFlagsEnum|SymbolFlagsValueModule) != 0 {
+ return c.getTypeOfFuncClassEnumModule(symbol)
+ }
+ // if symbol.flags&SymbolFlagsEnumMember != 0 {
+ // return c.getTypeOfEnumMember(symbol)
+ // }
+ // if symbol.flags&SymbolFlagsAccessor != 0 {
+ // return c.getTypeOfAccessors(symbol)
+ // }
+ // if symbol.flags&SymbolFlagsAlias != 0 {
+ // return c.getTypeOfAlias(symbol)
+ // }
+ return c.errorType
+}
+
+func (c *Checker) getTypeOfVariableOrParameterOrProperty(symbol *Symbol) *Type {
+ links := c.valueSymbolLinks.get(symbol)
+ if links.resolvedType == nil {
+ t := c.getTypeOfVariableOrParameterOrPropertyWorker(symbol)
+ if t == nil {
+ panic("Unexpected nil type")
+ }
+ // For a contextually typed parameter it is possible that a type has already
+ // been assigned (in assignTypeToParameterAndFixTypeParameters), and we want
+ // to preserve this type. In fact, we need to _prefer_ that type, but it won't
+ // be assigned until contextual typing is complete, so we need to defer in
+ // cases where contextual typing may take place.
+ if links.resolvedType == nil && !c.isParameterOfContextSensitiveSignature(symbol) {
+ links.resolvedType = t
+ }
+ return t
+ }
+ return links.resolvedType
+}
+
+func (c *Checker) isParameterOfContextSensitiveSignature(symbol *Symbol) bool {
+ return false // !!!
+}
+
+func (c *Checker) getTypeOfVariableOrParameterOrPropertyWorker(symbol *Symbol) *Type {
+ // Handle prototype property
+ if symbol.flags&SymbolFlagsPrototype != 0 {
+ return c.getTypeOfPrototypeProperty(symbol)
+ }
+ // CommonsJS require and module both have type any.
+ if symbol == c.requireSymbol {
+ return c.anyType
+ }
+ // !!! Debug.assertIsDefined(symbol.valueDeclaration)
+ declaration := symbol.valueDeclaration
+ // !!! Handle export default expressions
+ // if isSourceFile(declaration) && isJsonSourceFile(declaration) {
+ // if !declaration.statements.length {
+ // return c.emptyObjectType
+ // }
+ // return c.getWidenedType(c.getWidenedLiteralType(c.checkExpression(declaration.statements[0].expression)))
+ // }
+ // Handle variable, parameter or property
+ if !c.pushTypeResolution(symbol, TypeSystemPropertyNameType) {
+ return c.reportCircularityError(symbol)
+ }
+ var result *Type
+ switch declaration.kind {
+ case SyntaxKindParameter, SyntaxKindPropertyDeclaration, SyntaxKindPropertySignature, SyntaxKindVariableDeclaration,
+ SyntaxKindBindingElement:
+ result = c.getWidenedTypeForVariableLikeDeclaration(declaration, true /*reportErrors*/)
+ case SyntaxKindExportAssignment:
+ result = c.widenTypeForVariableLikeDeclaration(c.checkExpressionCached(declaration.AsExportAssignment().expression), declaration, false /*reportErrors*/)
+ case SyntaxKindBinaryExpression:
+ result = c.getWidenedTypeForAssignmentDeclaration(symbol, nil)
+ case SyntaxKindJsxAttribute:
+ result = c.checkJsxAttribute(declaration.AsJsxAttribute(), CheckModeNormal)
+ case SyntaxKindEnumMember:
+ result = c.getTypeOfEnumMember(symbol)
+ default:
+ panic("Unhandled case in getTypeOfVariableOrParameterOrPropertyWorker")
+ }
+ if !c.popTypeResolution() {
+ return c.reportCircularityError(symbol)
+ }
+ return result
+}
+
+// Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type
+// specified in a type annotation or inferred from an initializer. However, in the case of a destructuring declaration it
+// is a bit more involved. For example:
+//
+// var [x, s = ""] = [1, "one"];
+//
+// Here, the array literal [1, "one"] is contextually typed by the type [any, string], which is the implied type of the
+// binding pattern [x, s = ""]. Because the contextual type is a tuple type, the resulting type of [1, "one"] is the
+// tuple type [number, string]. Thus, the type inferred for 'x' is number and the type inferred for 's' is string.
+func (c *Checker) getWidenedTypeForVariableLikeDeclaration(declaration *Node, reportErrors bool) *Type {
+ return c.widenTypeForVariableLikeDeclaration(c.getTypeForVariableLikeDeclaration(declaration /*includeOptionality*/, true, CheckModeNormal), declaration, reportErrors)
+}
+
+// Return the inferred type for a variable, parameter, or property declaration
+func (c *Checker) getTypeForVariableLikeDeclaration(declaration *Node, includeOptionality bool, checkMode CheckMode) *Type {
+ // A variable declared in a for..in statement is of type string, or of type keyof T when the
+ // right hand expression is of a type parameter type.
+ if isVariableDeclaration(declaration) {
+ grandParent := declaration.parent.parent
+ switch grandParent.kind {
+ case SyntaxKindForInStatement:
+ // !!!
+ // indexType := c.getIndexType(c.getNonNullableTypeIfNeeded(c.checkExpression(declaration.parent.parent.expression /*checkMode*/, checkMode)))
+ // if indexType.flags & (TypeFlagsTypeParameter | TypeFlagsIndex) {
+ // return c.getExtractStringType(indexType)
+ // } else {
+ // return c.stringType
+ // }
+ return c.stringType
+ case SyntaxKindForOfStatement:
+ // checkRightHandSideOfForOf will return undefined if the for-of expression type was
+ // missing properties/signatures required to get its iteratedType (like
+ // [Symbol.iterator] or next). This may be because we accessed properties from anyType,
+ // or it may have led to an error inside getElementTypeOfIterable.
+ return c.checkRightHandSideOfForOf(grandParent)
+ }
+ } else if isBindingElement(declaration) {
+ return c.getTypeForBindingElement(declaration)
+ }
+ isProperty := isPropertyDeclaration(declaration) && !hasAccessorModifier(declaration) || isPropertySignatureDeclaration(declaration)
+ isOptional := includeOptionality && isOptionalDeclaration(declaration)
+ // Use type from type annotation if one is present
+ declaredType := c.tryGetTypeFromEffectiveTypeNode(declaration)
+ if isCatchClauseVariableDeclarationOrBindingElement(declaration) {
+ if declaredType != nil {
+ // If the catch clause is explicitly annotated with any or unknown, accept it, otherwise error.
+ if declaredType.flags&TypeFlagsAnyOrUnknown != 0 {
+ return declaredType
+ }
+ return c.errorType
+ }
+ // If the catch clause is not explicitly annotated, treat it as though it were explicitly
+ // annotated with unknown or any, depending on useUnknownInCatchVariables.
+ if c.useUnknownInCatchVariables {
+ return c.unknownType
+ } else {
+ return c.anyType
+ }
+ }
+ if declaredType != nil {
+ return c.addOptionalityEx(declaredType, isProperty, isOptional)
+ }
+ if c.noImplicitAny && isVariableDeclaration(declaration) && !isBindingPattern(declaration.Name()) &&
+ c.getCombinedModifierFlagsCached(declaration)&ModifierFlagsExport == 0 && declaration.flags&NodeFlagsAmbient == 0 {
+ // If --noImplicitAny is on or the declaration is in a Javascript file,
+ // use control flow tracked 'any' type for non-ambient, non-exported var or let variables with no
+ // initializer or a 'null' or 'undefined' initializer.
+ variableDeclaration := declaration.AsVariableDeclaration()
+ if c.getCombinedNodeFlagsCached(declaration)&NodeFlagsConstant == 0 && (variableDeclaration.initializer == nil || c.isNullOrUndefined(variableDeclaration.initializer)) {
+ return c.autoType
+ }
+ // Use control flow tracked 'any[]' type for non-ambient, non-exported variables with an empty array
+ // literal initializer.
+ if variableDeclaration.initializer != nil && isEmptyArrayLiteral(variableDeclaration.initializer) {
+ return c.anyType // !!!
+ // return c.autoArrayType
+ }
+ }
+ if isParameter(declaration) {
+ // !!!
+ // if declaration.Symbol() == nil {
+ // // parameters of function types defined in JSDoc in TS files don't have symbols
+ // return nil
+ // }
+ // fn := declaration.parent.(FunctionLikeDeclaration)
+ // // For a parameter of a set accessor, use the type of the get accessor if one is present
+ // if fn.kind == SyntaxKindSetAccessor && c.hasBindableName(fn) {
+ // getter := getDeclarationOfKind(c.getSymbolOfDeclaration(declaration.parent), SyntaxKindGetAccessor)
+ // if getter != nil {
+ // getterSignature := c.getSignatureFromDeclaration(getter)
+ // thisParameter := c.getAccessorThisParameter(fn.(AccessorDeclaration))
+ // if thisParameter && declaration == thisParameter {
+ // // Use the type from the *getter*
+ // Debug.assert(!thisParameter.type_)
+ // return c.getTypeOfSymbol(getterSignature.thisParameter)
+ // }
+ // return c.getReturnTypeOfSignature(getterSignature)
+ // }
+ // }
+ // parameterTypeOfTypeTag := c.getParameterTypeOfTypeTag(fn, declaration)
+ // if parameterTypeOfTypeTag {
+ // return parameterTypeOfTypeTag
+ // }
+ // // Use contextual parameter type if one is available
+ // var type_ *Type
+ // if declaration.symbol.escapedName == InternalSymbolNameThis {
+ // type_ = c.getContextualThisParameterType(fn)
+ // } else {
+ // type_ = c.getContextuallyTypedParameterType(declaration)
+ // }
+ // if type_ {
+ // return c.addOptionality(type_ /*isProperty*/, false, isOptional)
+ // }
+ }
+ // Use the type of the initializer expression if one is present and the declaration is
+ // not a parameter of a contextually typed function
+ if getInitializerFromNode(declaration) != nil {
+ t := c.widenTypeInferredFromInitializer(declaration, c.checkDeclarationInitializer(declaration, checkMode, nil /*contextualType*/))
+ return c.addOptionalityEx(t, isProperty, isOptional)
+ }
+ if c.noImplicitAny && isPropertyDeclaration(declaration) {
+ // We have a property declaration with no type annotation or initializer, in noImplicitAny mode or a .js file.
+ // Use control flow analysis of this.xxx assignments in the constructor or static block to determine the type of the property.
+ if !hasStaticModifier(declaration) {
+ return nil
+ // !!!
+ // constructor := findConstructorDeclaration(declaration.parent.(ClassLikeDeclaration))
+ // var t *Type
+ // switch {
+ // case constructor != nil:
+ // t = c.getFlowTypeInConstructor(declaration.symbol, constructor)
+ // case getEffectiveModifierFlags(declaration)&ModifierFlagsAmbient != 0:
+ // t = c.getTypeOfPropertyInBaseClass(declaration.symbol)
+ // }
+ // if t != nil {
+ // t = c.addOptionalityEx(t, true /*isProperty*/, isOptional)
+ // }
+ // return t
+ } else {
+ return nil
+ // !!!
+ // staticBlocks := filter(declaration.parent.(ClassLikeDeclaration).Members(), isClassStaticBlockDeclaration)
+ // var t *Type
+ // switch {
+ // case len(staticBlocks) != 0:
+ // t = c.getFlowTypeInStaticBlocks(declaration.symbol, staticBlocks)
+ // case getEffectiveModifierFlags(declaration)&ModifierFlagsAmbient != 0:
+ // t = c.getTypeOfPropertyInBaseClass(declaration.symbol)
+ // }
+ // if t != nil {
+ // t = c.addOptionalityEx(t, true /*isProperty*/, isOptional)
+ // }
+ // return t
+ }
+ }
+ if isJsxAttribute(declaration) {
+ // if JSX attribute doesn't have initializer, by default the attribute will have boolean value of true.
+ // I.e is sugar for
+ return c.trueType
+ }
+ // If the declaration specifies a binding pattern and is not a parameter of a contextually
+ // typed function, use the type implied by the binding pattern
+ if isBindingPattern(declaration.Name()) {
+ return c.getTypeFromBindingPattern(declaration.Name() /*includePatternInType*/, false /*reportErrors*/, true)
+ }
+ // No type specified and nothing can be inferred
+ return nil
+}
+
+func (c *Checker) checkDeclarationInitializer(declaration *Node, checkMode CheckMode, contextualType *Type) *Type {
+ initializer := c.getEffectiveInitializer(declaration)
+ t := c.getQuickTypeOfExpression(initializer)
+ if t == nil {
+ if contextualType != nil {
+ t = c.checkExpressionWithContextualType(initializer, contextualType, nil /*inferenceContext*/, checkMode)
+ } else {
+ t = c.checkExpressionCachedEx(initializer, checkMode)
+ }
+ }
+ if isParameter(getRootDeclaration(declaration)) {
+ name := declaration.Name()
+ switch name.kind {
+ case SyntaxKindObjectBindingPattern:
+ if isObjectLiteralType(t) {
+ return c.padObjectLiteralType(t, name)
+ }
+ case SyntaxKindArrayBindingPattern:
+ if isTupleType(t) {
+ return c.padTupleType(t, name)
+ }
+ }
+ }
+ return t
+}
+
+func (c *Checker) padObjectLiteralType(t *Type, pattern *Node) *Type {
+ return t
+}
+
+func (c *Checker) padTupleType(t *Type, pattern *Node) *Type {
+ return t
+}
+
+func (c *Checker) getEffectiveInitializer(declaration *Node) *Node {
+ return getInitializerFromNode(declaration)
+}
+
+func (c *Checker) widenTypeInferredFromInitializer(declaration *Node, t *Type) *Type {
+ if c.getCombinedNodeFlagsCached(declaration)&NodeFlagsConstant != 0 || isDeclarationReadonly(declaration) {
+ return t
+ }
+ return c.getWidenedLiteralType(t)
+}
+
+func (c *Checker) getTypeOfFuncClassEnumModule(symbol *Symbol) *Type {
+ links := c.valueSymbolLinks.get(symbol)
+ if links.resolvedType == nil {
+ links.resolvedType = c.getTypeOfFuncClassEnumModuleWorker(symbol)
+ }
+ return links.resolvedType
+}
+
+func (c *Checker) getTypeOfFuncClassEnumModuleWorker(symbol *Symbol) *Type {
+ if symbol.flags&SymbolFlagsModule != 0 && isShorthandAmbientModuleSymbol(symbol) {
+ return c.anyType
+ }
+ t := c.newObjectType(ObjectFlagsAnonymous, symbol)
+ if symbol.flags&SymbolFlagsClass != 0 {
+ baseTypeVariable := c.getBaseTypeVariableOfClass(symbol)
+ if baseTypeVariable != nil {
+ return c.getIntersectionType(t, baseTypeVariable)
+ }
+ return t
+ }
+ if c.strictNullChecks && symbol.flags&SymbolFlagsOptional != 0 {
+ return c.getOptionalType(t /*isProperty*/, true)
+ }
+ return t
+}
+
+func (c *Checker) getBaseTypeVariableOfClass(symbol *Symbol) *Type {
+ baseConstructorType := c.getBaseConstructorTypeOfClass(c.getDeclaredTypeOfClassOrInterface(symbol))
+ switch {
+ case baseConstructorType.flags&TypeFlagsTypeVariable != 0:
+ return baseConstructorType
+ case baseConstructorType.flags&TypeFlagsIntersection != 0:
+ return find(baseConstructorType.IntersectionType().types, func(t *Type) bool {
+ return t.flags&TypeFlagsTypeVariable != 0
+ })
+ }
+ return nil
+}
+
+func (c *Checker) getBaseConstructorTypeOfClass(t *Type) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) getDeclaredTypeOfClassOrInterface(symbol *Symbol) *Type {
+ links := c.interfaceTypeLinks.get(symbol)
+ if links.declaredType == nil {
+ kind := ifElse(symbol.flags&SymbolFlagsClass != 0, ObjectFlagsClass, ObjectFlagsInterface)
+ t := c.newInterfaceType(kind, symbol)
+ links.declaredType = t
+ outerTypeParameters := c.getOuterTypeParametersOfClassOrInterface(symbol)
+ localTypeParameters := c.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)
+ // A class or interface is generic if it has type parameters or a "this" type. We always give classes a "this" type
+ // because it is not feasible to analyze all members to determine if the "this" type escapes the class (in particular,
+ // property types inferred from initializers and method return types inferred from return statements are very hard
+ // to exhaustively analyze). We give interfaces a "this" type if we can't definitely determine that they are free of
+ // "this" references.
+ if outerTypeParameters != nil || localTypeParameters != nil || kind == ObjectFlagsClass || !c.isThislessInterface(symbol) {
+ t.objectFlags |= ObjectFlagsReference
+ d := t.InterfaceType()
+ d.thisType = c.newTypeParameter(symbol)
+ d.thisType.TypeParameter().isThisType = true
+ d.thisType.TypeParameter().constraint = t
+ // Allocate room for all type parameters plus the extra thisType
+ d.typeParameters = append(append(make([]*Type, 0, len(outerTypeParameters)+len(localTypeParameters)+1), outerTypeParameters...), localTypeParameters...)
+ // Append thisType such that t.typeParameters[:len(t.typeParameters)+1] yields the full list
+ _ = append(d.typeParameters, d.thisType)
+ d.resolvedTypeArguments = d.typeParameters
+ d.outerTypeParameters = outerTypeParameters
+ d.localTypeParameters = localTypeParameters
+ d.instantiations = make(map[string]*Type)
+ d.instantiations[getTypeListId(d.resolvedTypeArguments)] = t
+ d.target = t
+ }
+ }
+ return links.declaredType
+}
+
+func (c *Checker) isThislessInterface(symbol *Symbol) bool {
+ return true // !!!
+}
+
+func getTypeListId(types []*Type) string {
+ var sb strings.Builder
+ writeTypes(&sb, types)
+ return sb.String()
+}
+
+func getAliasId(alias *TypeAlias) string {
+ var sb strings.Builder
+ writeAlias(&sb, alias)
+ return sb.String()
+}
+
+func getUnionId(types []*Type, origin *Type, alias *TypeAlias) string {
+ var sb strings.Builder
+ switch {
+ case origin == nil:
+ writeTypes(&sb, types)
+ case origin.flags&TypeFlagsUnion != 0:
+ sb.WriteByte('|')
+ writeTypes(&sb, origin.UnionType().types)
+ case origin.flags&TypeFlagsIntersection != 0:
+ sb.WriteByte('&')
+ writeTypes(&sb, origin.IntersectionType().types)
+ case origin.flags&TypeFlagsIndex != 0:
+ // origin type id alone is insufficient, as `keyof x` may resolve to multiple WIP values while `x` is still resolving
+ sb.WriteByte('#')
+ writeUint32(&sb, uint32(origin.id))
+ sb.WriteByte('|')
+ writeTypes(&sb, types)
+ default:
+ panic("Unhandled case in getUnionId")
+ }
+ if alias != nil {
+ writeAlias(&sb, alias)
+ }
+ return sb.String()
+}
+
+func writeTypes(sb *strings.Builder, types []*Type) {
+ i := 0
+ for i < len(types) {
+ startId := types[i].id
+ count := 1
+ for i+count < len(types) && types[i+count].id == startId+TypeId(count) {
+ count++
+ }
+ if sb.Len() != 0 {
+ sb.WriteByte(',')
+ }
+ writeUint32(sb, uint32(startId))
+ if count > 1 {
+ sb.WriteByte(':')
+ writeUint32(sb, uint32(count))
+ }
+ i += count
+ }
+}
+
+func writeAlias(sb *strings.Builder, alias *TypeAlias) {
+ sb.WriteByte('@')
+ writeUint32(sb, uint32(getSymbolId(alias.symbol)))
+ if len(alias.typeArguments) != 0 {
+ sb.WriteByte(':')
+ writeTypes(sb, alias.typeArguments)
+ }
+}
+
+var base64chars = []byte{
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
+ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+ 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '$', '?'}
+
+func writeUint32(sb *strings.Builder, value uint32) {
+ for value != 0 {
+ sb.WriteByte(base64chars[value&0x3F])
+ value >>= 6
+ }
+}
+
+func (c *Checker) isNullOrUndefined(node *Node) bool {
+ expr := skipParentheses(node)
+ switch expr.kind {
+ case SyntaxKindNullKeyword:
+ return true
+ case SyntaxKindIdentifier:
+ return c.getResolvedSymbol(expr) == c.undefinedSymbol
+ }
+ return false
+}
+
+func (c *Checker) checkRightHandSideOfForOf(statement *Node) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) getTypeForBindingElement(declaration *Node) *Type {
+ return c.anyType // !!!
+}
+
+// Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself
+// and without regard to its context (i.e. without regard any type annotation or initializer associated with the
+// declaration in which the binding pattern is contained). For example, the implied type of [x, y] is [any, any]
+// and the implied type of { x, y: z = 1 } is { x: any; y: number; }. The type implied by a binding pattern is
+// used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring
+// parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of
+// the parameter.
+func (c *Checker) getTypeFromBindingPattern(pattern *Node, includePatternInType bool, reportErrors bool) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) getTypeOfPrototypeProperty(prototype *Symbol) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) getWidenedTypeForAssignmentDeclaration(symbol *Symbol, resolvedSymbol *Symbol) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) widenTypeForVariableLikeDeclaration(t *Type, declaration *Node, reportErrors bool) *Type {
+ if t != nil {
+ return t
+ // !!!
+ // // TODO: If back compat with pre-3.0/4.0 libs isn't required, remove the following SymbolConstructor special case transforming `symbol` into `unique symbol`
+ // if t.flags&TypeFlagsESSymbol != 0 && c.isGlobalSymbolConstructor(declaration.parent) {
+ // t = c.getESSymbolLikeTypeForNode(declaration)
+ // }
+ // if reportErrors {
+ // c.reportErrorsFromWidening(declaration, t)
+ // }
+ // // always widen a 'unique symbol' type if the type was created for a different declaration.
+ // if t.flags&TypeFlagsUniqueESSymbol && (isBindingElement(declaration) || !declaration.type_) && t.symbol != c.getSymbolOfDeclaration(declaration) {
+ // t = c.esSymbolType
+ // }
+ // return c.getWidenedType(t)
+ }
+ // Rest parameters default to type any[], other parameters default to type any
+ if isParameter(declaration) && declaration.AsParameterDeclaration().dotDotDotToken != nil {
+ t = c.anyArrayType
+ } else {
+ t = c.anyType
+ }
+ // Report implicit any errors unless this is a private property within an ambient declaration
+ if reportErrors {
+ if !declarationBelongsToPrivateAmbientMember(declaration) {
+ c.reportImplicitAny(declaration, t, WideningKindNormal)
+ }
+ }
+ return t
+}
+
+func (c *Checker) reportImplicitAny(declaration *Node, t *Type, wideningKind WideningKind) {
+ typeAsString := c.typeToString(c.getWidenedType(t))
+ var diagnostic *diagnostics.Message
+ switch declaration.kind {
+ case SyntaxKindBinaryExpression, SyntaxKindPropertyDeclaration, SyntaxKindPropertySignature:
+ diagnostic = ifElse(c.noImplicitAny,
+ diagnostics.Member_0_implicitly_has_an_1_type,
+ diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage)
+ case SyntaxKindParameter:
+ param := declaration.AsParameterDeclaration()
+ if isIdentifier(param.name) {
+ name := param.name.AsIdentifier()
+ originalKeywordKind := identifierToKeywordKind(name)
+ if (isCallSignatureDeclaration(declaration.parent) || isMethodSignatureDeclaration(declaration.parent) || isFunctionTypeNode(declaration.parent)) &&
+ slices.Contains(declaration.parent.FunctionLikeData().parameters, declaration) &&
+ (isTypeNodeKind(originalKeywordKind) || c.resolveName(declaration, name.text, SymbolFlagsType, nil /*nameNotFoundMessage*/, true /*isUse*/, false /*excludeGlobals*/) != nil) {
+ newName := fmt.Sprintf("arg%v", slices.Index(declaration.parent.FunctionLikeData().parameters, declaration))
+ typeName := declarationNameToString(param.name) + ifElse(param.dotDotDotToken != nil, "[]", "")
+ c.errorOrSuggestion(c.noImplicitAny, declaration, diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, newName, typeName)
+ return
+ }
+ }
+ switch {
+ case param.dotDotDotToken != nil:
+ if c.noImplicitAny {
+ diagnostic = diagnostics.Rest_parameter_0_implicitly_has_an_any_type
+ } else {
+ diagnostic = diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage
+ }
+ case c.noImplicitAny:
+ diagnostic = diagnostics.Parameter_0_implicitly_has_an_1_type
+ default:
+ diagnostic = diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage
+ }
+ case SyntaxKindBindingElement:
+ diagnostic = diagnostics.Binding_element_0_implicitly_has_an_1_type
+ if !c.noImplicitAny {
+ // Don't issue a suggestion for binding elements since the codefix doesn't yet support them.
+ return
+ }
+ case SyntaxKindFunctionDeclaration, SyntaxKindMethodDeclaration, SyntaxKindMethodSignature, SyntaxKindGetAccessor,
+ SyntaxKindSetAccessor, SyntaxKindFunctionExpression, SyntaxKindArrowFunction:
+ if c.noImplicitAny && declaration.Name() == nil {
+ if wideningKind == WideningKindGeneratorYield {
+ c.error(declaration, diagnostics.Generator_implicitly_has_yield_type_0_Consider_supplying_a_return_type_annotation, typeAsString)
+ } else {
+ c.error(declaration, diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString)
+ }
+ return
+ }
+ switch {
+ case !c.noImplicitAny:
+ diagnostic = diagnostics.X_0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage
+ case wideningKind == WideningKindGeneratorYield:
+ diagnostic = diagnostics.X_0_which_lacks_return_type_annotation_implicitly_has_an_1_yield_type
+ default:
+ diagnostic = diagnostics.X_0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type
+ }
+ case SyntaxKindMappedType:
+ if c.noImplicitAny {
+ c.error(declaration, diagnostics.Mapped_object_type_implicitly_has_an_any_template_type)
+ }
+ return
+ default:
+ if c.noImplicitAny {
+ diagnostic = diagnostics.Variable_0_implicitly_has_an_1_type
+ } else {
+ diagnostic = diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage
+ }
+ }
+ c.errorOrSuggestion(c.noImplicitAny, declaration, diagnostic, declarationNameToString(getNameOfDeclaration(declaration)), typeAsString)
+}
+
+func (c *Checker) getWidenedType(t *Type) *Type {
+ return t // !!!
+}
+
+func (c *Checker) getTypeOfEnumMember(symbol *Symbol) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) addOptionalityEx(t *Type, isProperty bool, isOptional bool) *Type {
+ if c.strictNullChecks && isOptional {
+ return c.getOptionalType(t, isProperty)
+ }
+ return t
+}
+
+func (c *Checker) getOptionalType(t *Type, isProperty bool) *Type {
+ // !!! Debug.assert(c.strictNullChecks)
+ missingOrUndefined := ifElse(isProperty, c.undefinedOrMissingType, c.undefinedType)
+ if t == missingOrUndefined || t.flags&TypeFlagsUnion != 0 && t.UnionType().types[0] == missingOrUndefined {
+ return t
+ }
+ return c.getUnionType([]*Type{t, missingOrUndefined})
+}
+
+func (c *Checker) getDeclarationNodeFlagsFromSymbol(s *Symbol) NodeFlags {
+ if s.valueDeclaration != nil {
+ return c.getCombinedNodeFlagsCached(s.valueDeclaration)
+ }
+ return NodeFlagsNone
+}
+
+func (c *Checker) getCombinedNodeFlagsCached(node *Node) NodeFlags {
+ // we hold onto the last node and result to speed up repeated lookups against the same node.
+ if c.lastGetCombinedNodeFlagsNode == node {
+ return c.lastGetCombinedNodeFlagsResult
+ }
+ c.lastGetCombinedNodeFlagsNode = node
+ c.lastGetCombinedNodeFlagsResult = getCombinedNodeFlags(node)
+ return c.lastGetCombinedNodeFlagsResult
+}
+
+func (c *Checker) getCombinedModifierFlagsCached(node *Node) ModifierFlags {
+ // we hold onto the last node and result to speed up repeated lookups against the same node.
+ if c.lastGetCombinedModifierFlagsNode == node {
+ return c.lastGetCombinedModifierFlagsResult
+ }
+ c.lastGetCombinedModifierFlagsNode = node
+ c.lastGetCombinedModifierFlagsResult = getCombinedModifierFlags(node)
+ return c.lastGetCombinedModifierFlagsResult
+}
+
+/**
+ * Push an entry on the type resolution stack. If an entry with the given target and the given property name
+ * is already on the stack, and no entries in between already have a type, then a circularity has occurred.
+ * In this case, the result values of the existing entry and all entries pushed after it are changed to false,
+ * and the value false is returned. Otherwise, the new entry is just pushed onto the stack, and true is returned.
+ * In order to see if the same query has already been done before, the target object and the propertyName both
+ * must match the one passed in.
+ *
+ * @param target The symbol, type, or signature whose type is being queried
+ * @param propertyName The property name that should be used to query the target for its type
+ */
+func (c *Checker) pushTypeResolution(target TypeSystemEntity, propertyName TypeSystemPropertyName) bool {
+ resolutionCycleStartIndex := c.findResolutionCycleStartIndex(target, propertyName)
+ if resolutionCycleStartIndex >= 0 {
+ // A cycle was found
+ for i := resolutionCycleStartIndex; i < len(c.typeResolutions); i++ {
+ c.typeResolutions[i].result = false
+ }
+ return false
+ }
+ c.typeResolutions = append(c.typeResolutions, TypeResolution{target: target, propertyName: propertyName, result: true})
+ return true
+}
+
+/**
+ * Pop an entry from the type resolution stack and return its associated result value. The result value will
+ * be true if no circularities were detected, or false if a circularity was found.
+ */
+func (c *Checker) popTypeResolution() bool {
+ lastIndex := len(c.typeResolutions) - 1
+ result := c.typeResolutions[lastIndex].result
+ c.typeResolutions = c.typeResolutions[:lastIndex]
+ return result
+}
+
+func (c *Checker) findResolutionCycleStartIndex(target TypeSystemEntity, propertyName TypeSystemPropertyName) int {
+ for i := len(c.typeResolutions) - 1; i >= c.resolutionStart; i-- {
+ resolution := &c.typeResolutions[i]
+ if c.typeResolutionHasProperty(resolution) {
+ return -1
+ }
+ if resolution.target == target && resolution.propertyName == propertyName {
+ return i
+ }
+ }
+ return -1
+}
+
+func (c *Checker) typeResolutionHasProperty(r *TypeResolution) bool {
+ switch r.propertyName {
+ case TypeSystemPropertyNameType:
+ return c.valueSymbolLinks.get(r.target.(*Symbol)).resolvedType != nil
+ // !!!
+ // case TypeSystemPropertyNameDeclaredType:
+ // return !!c.getSymbolLinks(target.(Symbol)).declaredType
+ // case TypeSystemPropertyNameResolvedBaseConstructorType:
+ // return !!(target.(InterfaceType)).resolvedBaseConstructorType
+ // case TypeSystemPropertyNameResolvedReturnType:
+ // return !!(target.(Signature)).resolvedReturnType
+ // case TypeSystemPropertyNameImmediateBaseConstraint:
+ // return !!(target.(*Type)).immediateBaseConstraint
+ // case TypeSystemPropertyNameResolvedTypeArguments:
+ // return !!(target.(TypeReference)).resolvedTypeArguments
+ // case TypeSystemPropertyNameResolvedBaseTypes:
+ // return !!(target.(InterfaceType)).baseTypesResolved
+ // case TypeSystemPropertyNameWriteType:
+ // return !!c.getSymbolLinks(target.(Symbol)).writeType
+ // case TypeSystemPropertyNameParameterInitializerContainsUndefined:
+ // return c.getNodeLinks(target.(ParameterDeclaration)).parameterInitializerContainsUndefined != nil
+ }
+ panic("Unhandled case in typeResolutionHasProperty")
+}
+
+func (c *Checker) reportCircularityError(symbol *Symbol) *Type {
+ declaration := symbol.valueDeclaration
+ // Check if variable has type annotation that circularly references the variable itself
+ if declaration != nil {
+ if getEffectiveTypeAnnotationNode(declaration) != nil {
+ c.error(symbol.valueDeclaration, diagnostics.X_0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, c.symbolToString(symbol))
+ return c.errorType
+ }
+ // Check if variable has initializer that circularly references the variable itself
+ if c.noImplicitAny && (declaration.kind != SyntaxKindParameter || declaration.AsParameterDeclaration().initializer != nil) {
+ c.error(symbol.valueDeclaration, diagnostics.X_0_implicitly_has_type_any_because_it_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer, c.symbolToString(symbol))
+ }
+ } else if symbol.flags&SymbolFlagsAlias != 0 {
+ node := c.getDeclarationOfAliasSymbol(symbol)
+ if node != nil {
+ c.error(node, diagnostics.Circular_definition_of_import_alias_0, c.symbolToString(symbol))
+ }
+ }
+ // Circularities could also result from parameters in function expressions that end up
+ // having themselves as contextual types following type argument inference. In those cases
+ // we have already reported an implicit any error so we don't report anything here.
+ return c.anyType
+}
+
+func (c *Checker) getPropertiesOfType(t *Type) []*Symbol {
+ t = c.getReducedApparentType(t)
+ if t.flags&TypeFlagsUnionOrIntersection != 0 {
+ return c.getPropertiesOfUnionOrIntersectionType(t)
+ }
+ return c.getPropertiesOfObjectType(t)
+}
+
+func (c *Checker) getPropertiesOfObjectType(t *Type) []*Symbol {
+ if t.flags&TypeFlagsObject != 0 {
+ return c.resolveStructuredTypeMembers(t).properties
+ }
+ return nil
+}
+
+func (c *Checker) getPropertiesOfUnionOrIntersectionType(t *Type) []*Symbol {
+ return nil
+}
+
+func (c *Checker) getPropertyOfType(t *Type, name string) *Symbol {
+ return c.getPropertyOfTypeEx(t, name, false /*skipObjectFunctionPropertyAugment*/, false /*includeTypeOnlyMembers*/)
+}
+
+/**
+ * Return the symbol for the property with the given name in the given type. Creates synthetic union properties when
+ * necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from
+ * Object and Function as appropriate.
+ *
+ * @param type a type to look up property from
+ * @param name a name of property to look up in a given type
+ */
+func (c *Checker) getPropertyOfTypeEx(t *Type, name string, skipObjectFunctionPropertyAugment bool, includeTypeOnlyMembers bool) *Symbol {
+ t = c.getReducedApparentType(t)
+ switch {
+ case t.flags&TypeFlagsObject != 0:
+ resolved := c.resolveStructuredTypeMembers(t)
+ symbol := resolved.members[name]
+ if symbol != nil {
+ if !includeTypeOnlyMembers && t.symbol.flags&SymbolFlagsValueModule != 0 && c.moduleSymbolLinks.get(t.symbol).typeOnlyExportStarMap[name] != nil {
+ // If this is the type of a module, `resolved.members.get(name)` might have effectively skipped over
+ // an `export type * from './foo'`, leaving `symbolIsValue` unable to see that the symbol is being
+ // viewed through a type-only export.
+ return nil
+ }
+ if c.symbolIsValueEx(symbol, includeTypeOnlyMembers) {
+ return symbol
+ }
+ }
+ if !skipObjectFunctionPropertyAugment {
+ var functionType *Type
+ switch {
+ case t == c.anyFunctionType:
+ functionType = c.globalFunctionType
+ case len(resolved.callSignatures) != 0:
+ functionType = c.globalCallableFunctionType
+ case len(resolved.constructSignatures) != 0:
+ functionType = c.globalNewableFunctionType
+ }
+ if functionType != nil {
+ symbol = c.getPropertyOfObjectType(functionType, name)
+ if symbol != nil {
+ return symbol
+ }
+ }
+ return c.getPropertyOfObjectType(c.globalObjectType, name)
+ }
+ return nil
+ case t.flags&TypeFlagsIntersection != 0:
+ prop := c.getPropertyOfUnionOrIntersectionType(t, name, true /*skipObjectFunctionPropertyAugment*/)
+ if prop != nil {
+ return prop
+ }
+ if !skipObjectFunctionPropertyAugment {
+ return c.getPropertyOfUnionOrIntersectionType(t, name, skipObjectFunctionPropertyAugment)
+ }
+ return nil
+ case t.flags&TypeFlagsUnion != 0:
+ return c.getPropertyOfUnionOrIntersectionType(t, name, skipObjectFunctionPropertyAugment)
+ }
+ return nil
+}
+
+func (c *Checker) getSignaturesOfType(t *Type, kind SignatureKind) []*Signature {
+ return nil // !!!
+}
+
+func (c *Checker) getIndexInfosOfType(t *Type) []*IndexInfo {
+ return nil // !!!
+}
+
+func (c *Checker) resolveStructuredTypeMembers(t *Type) *ObjectTypeBase {
+ if t.objectFlags&ObjectFlagsMembersResolved == 0 {
+ switch {
+ case t.flags&TypeFlagsObject != 0:
+ switch {
+ case t.objectFlags&ObjectFlagsReference != 0:
+ c.resolveTypeReferenceMembers(t)
+ case t.objectFlags&ObjectFlagsClassOrInterface != 0:
+ c.resolveClassOrInterfaceMembers(t)
+ case t.objectFlags&ObjectFlagsReverseMapped != 0:
+ c.resolveReverseMappedTypeMembers(t)
+ case t.objectFlags&ObjectFlagsAnonymous != 0:
+ c.resolveAnonymousTypeMembers(t)
+ case t.objectFlags&ObjectFlagsMapped != 0:
+ c.resolveMappedTypeMembers(t)
+ default:
+ panic("Unhandled case in resolveStructuredTypeMembers")
+ }
+ case t.flags&TypeFlagsUnion != 0:
+ c.resolveUnionTypeMembers(t)
+ case t.flags&TypeFlagsIntersection != 0:
+ c.resolveIntersectionTypeMembers(t)
+ default:
+ panic("Unhandled case in resolveStructuredTypeMembers")
+ }
+ }
+ return t.ObjectType()
+}
+
+func (c *Checker) resolveClassOrInterfaceMembers(t *Type) {
+ c.resolveObjectTypeMembers(t, t, nil, nil)
+}
+
+func (c *Checker) resolveTypeReferenceMembers(t *Type) {
+ source := t.ParameterizedType().target
+ // Interface type construction guarantees thisType is stored just past type parameters
+ typeParameters := source.InterfaceType().typeParameters
+ typeParameters = typeParameters[:len(typeParameters)+1]
+ typeArguments := c.getTypeArguments(t)
+ paddedTypeArguments := typeArguments
+ if len(typeArguments) == len(typeParameters)-1 {
+ paddedTypeArguments = concatenate(typeArguments, []*Type{t})
+ }
+ c.resolveObjectTypeMembers(t, source, typeParameters, paddedTypeArguments)
+}
+
+func (c *Checker) resolveObjectTypeMembers(t *Type, source *Type, typeParameters []*Type, typeArguments []*Type) {
+ var mapper TypeMapper
+ var members SymbolTable
+ var callSignatures []*Signature
+ var constructSignatures []*Signature
+ var indexInfos []*IndexInfo
+ var instantiated bool
+ if slices.Equal(typeParameters, typeArguments) {
+ members = c.getMembersOfSymbol(source.symbol)
+ resolved := c.resolveDeclaredMembers(source)
+ callSignatures = resolved.declaredCallSignatures
+ constructSignatures = resolved.declaredConstructSignatures
+ indexInfos = resolved.declaredIndexInfos
+ } else {
+ instantiated = true
+ // !!!
+ // mapper = c.newTypeMapper(typeParameters, typeArguments)
+ // members = c.createInstantiatedSymbolTable(source.declaredProperties, mapper /*mappingThisOnly*/, typeParameters.length == 1)
+ // callSignatures = c.instantiateSignatures(source.declaredCallSignatures, mapper)
+ // constructSignatures = c.instantiateSignatures(source.declaredConstructSignatures, mapper)
+ // indexInfos = c.instantiateIndexInfos(source.declaredIndexInfos, mapper)
+ }
+ baseTypes := c.getBaseTypes(source)
+ if len(baseTypes) != 0 {
+ if !instantiated {
+ members = maps.Clone(members)
+ }
+ c.setStructuredTypeMembers(t, members, callSignatures, constructSignatures, indexInfos)
+ thisArgument := lastOrNil(typeArguments)
+ for _, baseType := range baseTypes {
+ instantiatedBaseType := baseType
+ if thisArgument != nil {
+ instantiatedBaseType = c.getTypeWithThisArgument(c.instantiateType(baseType, mapper), thisArgument, false /*needsApparentType*/)
+ }
+ c.addInheritedMembers(members, c.getPropertiesOfType(instantiatedBaseType))
+ callSignatures = concatenate(callSignatures, c.getSignaturesOfType(instantiatedBaseType, SignatureKindCall))
+ constructSignatures = concatenate(constructSignatures, c.getSignaturesOfType(instantiatedBaseType, SignatureKindConstruct))
+ var inheritedIndexInfos []*IndexInfo
+ if instantiatedBaseType != c.anyType {
+ inheritedIndexInfos = c.getIndexInfosOfType(instantiatedBaseType)
+ } else {
+ inheritedIndexInfos = []*IndexInfo{&IndexInfo{keyType: c.stringType, valueType: c.anyType}}
+ }
+ indexInfos = concatenate(indexInfos, filter(inheritedIndexInfos, func(info *IndexInfo) bool {
+ return findIndexInfo(indexInfos, info.keyType) != nil
+ }))
+ }
+ }
+ c.setStructuredTypeMembers(t, members, callSignatures, constructSignatures, indexInfos)
+}
+
+func findIndexInfo(indexInfos []*IndexInfo, keyType *Type) *IndexInfo {
+ return find(indexInfos, func(info *IndexInfo) bool { return info.keyType == keyType })
+}
+
+func (c *Checker) getBaseTypes(t *Type) []*Type {
+ return nil // !!!
+}
+
+func (c *Checker) getTypeWithThisArgument(t *Type, thisArgument *Type, needApparentType bool) *Type {
+ if t.objectFlags&ObjectFlagsReference != 0 {
+ target := t.TypeReference().target
+ typeArguments := c.getTypeArguments(t)
+ if len(target.InterfaceType().typeParameters) == len(typeArguments) {
+ if thisArgument == nil {
+ thisArgument = target.InterfaceType().thisType
+ }
+ return c.createTypeReference(target, concatenate(typeArguments, []*Type{thisArgument}))
+ }
+ return t
+ } else if t.flags&TypeFlagsIntersection != 0 {
+ types, same := sameMap(t.IntersectionType().types, func(t *Type) *Type { return c.getTypeWithThisArgument(t, thisArgument, needApparentType) })
+ if same {
+ return t
+ }
+ return c.getIntersectionType(types...)
+ }
+ if needApparentType {
+ return c.getApparentType(t)
+ }
+ return t
+}
+
+func (c *Checker) addInheritedMembers(symbols SymbolTable, baseSymbols []*Symbol) {
+ for _, base := range baseSymbols {
+ if !isStaticPrivateIdentifierProperty(base) {
+ if _, ok := symbols[base.name]; !ok {
+ symbols[base.name] = base
+ }
+ }
+ }
+}
+
+func (c *Checker) resolveDeclaredMembers(t *Type) *InterfaceTypeData {
+ d := t.InterfaceType()
+ if !d.declaredMembersResolved {
+ d.declaredMembersResolved = true
+ members := c.getMembersOfSymbol(t.symbol)
+ d.declaredCallSignatures = c.getSignaturesOfSymbol(members[InternalSymbolNameCall])
+ d.declaredConstructSignatures = c.getSignaturesOfSymbol(members[InternalSymbolNameNew])
+ d.declaredIndexInfos = c.getIndexInfosOfSymbol(t.symbol)
+ }
+ return d
+}
+
+func (c *Checker) getIndexInfosOfSymbol(symbol *Symbol) []*IndexInfo {
+ indexSymbol := c.getIndexSymbol(symbol)
+ if indexSymbol != nil {
+ return c.getIndexInfosOfIndexSymbol(indexSymbol, slices.Collect(maps.Values(c.getMembersOfSymbol(symbol))))
+ }
+ return nil
+}
+
+func (c *Checker) getIndexInfosOfIndexSymbol(indexSymbol *Symbol, siblingSymbols []*Symbol) []*IndexInfo {
+ return nil // !!!
+}
+
+func (c *Checker) getIndexSymbol(symbol *Symbol) *Symbol {
+ return c.getMembersOfSymbol(symbol)[InternalSymbolNameIndex]
+}
+
+func (c *Checker) getSignaturesOfSymbol(symbol *Symbol) []*Signature {
+ return nil
+}
+
+func (c *Checker) resolveAnonymousTypeMembers(t *Type) {
+ d := t.AnonymousType()
+ if d.target != nil {
+ c.setStructuredTypeMembers(t, nil, nil, nil, nil)
+ // members := c.createInstantiatedSymbolTable(c.getPropertiesOfObjectType(t.target), t.mapper /*mappingThisOnly*/, false)
+ // callSignatures := c.instantiateSignatures(c.getSignaturesOfType(t.target, SignatureKindCall), t.mapper)
+ // constructSignatures := c.instantiateSignatures(c.getSignaturesOfType(t.target, SignatureKindConstruct), t.mapper)
+ // indexInfos := c.instantiateIndexInfos(c.getIndexInfosOfType(t.target), t.mapper)
+ // c.setStructuredTypeMembers(t, members, callSignatures, constructSignatures, indexInfos)
+ return
+ }
+ symbol := c.getMergedSymbol(t.symbol)
+ if symbol.flags&SymbolFlagsTypeLiteral != 0 {
+ c.setStructuredTypeMembers(t, nil, nil, nil, nil)
+ members := c.getMembersOfSymbol(symbol)
+ callSignatures := c.getSignaturesOfSymbol(members[InternalSymbolNameCall])
+ constructSignatures := c.getSignaturesOfSymbol(members[InternalSymbolNameNew])
+ indexInfos := c.getIndexInfosOfSymbol(symbol)
+ c.setStructuredTypeMembers(t, members, callSignatures, constructSignatures, indexInfos)
+ return
+ }
+ // Combinations of function, class, enum and module
+ members := c.getExportsOfSymbol(symbol)
+ var indexInfos []*IndexInfo
+ if symbol == c.globalThisSymbol {
+ varsOnly := make(SymbolTable)
+ for _, p := range members {
+ if p.flags&SymbolFlagsBlockScoped == 0 && !(p.flags&SymbolFlagsValueModule != 0 && len(p.declarations) != 0 && every(p.declarations, isAmbientModule)) {
+ varsOnly[p.name] = p
+ }
+ }
+ members = varsOnly
+ }
+ var baseConstructorIndexInfo *IndexInfo
+ c.setStructuredTypeMembers(t, members, nil, nil, nil)
+ if symbol.flags&SymbolFlagsClass != 0 {
+ classType := c.getDeclaredTypeOfClassOrInterface(symbol)
+ baseConstructorType := c.getBaseConstructorTypeOfClass(classType)
+ if baseConstructorType.flags&(TypeFlagsObject|TypeFlagsIntersection|TypeFlagsTypeVariable) != 0 {
+ members = maps.Clone(members)
+ c.addInheritedMembers(members, c.getPropertiesOfType(baseConstructorType))
+ c.setStructuredTypeMembers(t, members, nil, nil, nil)
+ } else if baseConstructorType == c.anyType {
+ baseConstructorIndexInfo = &IndexInfo{keyType: c.stringType, valueType: c.anyType}
+ }
+ }
+ indexSymbol := members[InternalSymbolNameIndex]
+ if indexSymbol != nil {
+ indexInfos = c.getIndexInfosOfIndexSymbol(indexSymbol, slices.Collect(maps.Values(members)))
+ } else {
+ if baseConstructorIndexInfo != nil {
+ indexInfos = append(indexInfos, baseConstructorIndexInfo)
+ }
+ if symbol.flags&SymbolFlagsEnum != 0 && (c.getDeclaredTypeOfSymbol(symbol).flags&TypeFlagsEnum != 0 || some(d.properties, func(prop *Symbol) bool {
+ return c.getTypeOfSymbol(prop).flags&TypeFlagsNumberLike != 0
+ })) {
+ indexInfos = append(indexInfos, c.enumNumberIndexInfo)
+ }
+ }
+ d.indexInfos = indexInfos
+ // We resolve the members before computing the signatures because a signature may use
+ // typeof with a qualified name expression that circularly references the type we are
+ // in the process of resolving (see issue #6072). The temporarily empty signature list
+ // will never be observed because a qualified name can't reference signatures.
+ if symbol.flags&(SymbolFlagsFunction|SymbolFlagsMethod) != 0 {
+ d.callSignatures = c.getSignaturesOfSymbol(symbol)
+ }
+ // And likewise for construct signatures for classes
+ if symbol.flags&SymbolFlagsClass != 0 {
+ classType := c.getDeclaredTypeOfClassOrInterface(symbol)
+ constructSignatures := c.getSignaturesOfSymbol(symbol.members[InternalSymbolNameConstructor])
+ if len(constructSignatures) == 0 {
+ constructSignatures = c.getDefaultConstructSignatures(classType)
+ }
+ d.constructSignatures = constructSignatures
+ }
+}
+
+func (c *Checker) getDefaultConstructSignatures(classType *Type) []*Signature {
+ return nil // !!!
+ // baseConstructorType := c.getBaseConstructorTypeOfClass(classType)
+ // baseSignatures := c.getSignaturesOfType(baseConstructorType, SignatureKindConstruct)
+ // declaration := getClassLikeDeclarationOfSymbol(classType.symbol)
+ // isAbstract := declaration != nil && hasSyntacticModifier(declaration, ModifierFlagsAbstract)
+ // if len(baseSignatures) == 0 {
+ // return []*Signature{c.createSignature(nil, classType.localTypeParameters /*thisParameter*/, nil, emptyArray, classType /*resolvedTypePredicate*/, nil, 0, ifelse(isAbstract, SignatureFlagsAbstract, SignatureFlagsNone))}
+ // }
+ // baseTypeNode := c.getBaseTypeNodeOfClass(classType)
+ // isJavaScript := isInJSFile(baseTypeNode)
+ // typeArguments := c.typeArgumentsFromTypeReferenceNode(baseTypeNode)
+ // typeArgCount := length(typeArguments)
+ // var result []Signature = []never{}
+ // for _, baseSig := range baseSignatures {
+ // minTypeArgumentCount := c.getMinTypeArgumentCount(baseSig.typeParameters)
+ // typeParamCount := length(baseSig.typeParameters)
+ // if isJavaScript || typeArgCount >= minTypeArgumentCount && typeArgCount <= typeParamCount {
+ // var sig Signature
+ // if typeParamCount {
+ // sig = c.createSignatureInstantiation(baseSig, c.fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, isJavaScript))
+ // } else {
+ // sig = c.cloneSignature(baseSig)
+ // }
+ // sig.typeParameters = classType.localTypeParameters
+ // sig.resolvedReturnType = classType
+ // if isAbstract {
+ // sig.flags = sig.flags | SignatureFlagsAbstract
+ // } else {
+ // sig.flags = sig.flags & ~SignatureFlagsAbstract
+ // }
+ // result.push(sig)
+ // }
+ // }
+ // return result
+}
+
+func (c *Checker) resolveMappedTypeMembers(t *Type) {
+ // !!!
+ c.setStructuredTypeMembers(t, nil, nil, nil, nil)
+}
+
+func (c *Checker) resolveReverseMappedTypeMembers(t *Type) {
+ // !!!
+ c.setStructuredTypeMembers(t, nil, nil, nil, nil)
+}
+
+func (c *Checker) resolveUnionTypeMembers(t *Type) {
+ // !!!
+ c.setStructuredTypeMembers(t, nil, nil, nil, nil)
+}
+
+func (c *Checker) resolveIntersectionTypeMembers(t *Type) {
+ // !!!
+ c.setStructuredTypeMembers(t, nil, nil, nil, nil)
+}
+
+/**
+ * If the given type is an object type and that type has a property by the given name,
+ * return the symbol for that property. Otherwise return undefined.
+ */
+func (c *Checker) getPropertyOfObjectType(t *Type, name string) *Symbol {
+ if t.flags&TypeFlagsObject != 0 {
+ resolved := c.resolveStructuredTypeMembers(t)
+ symbol := resolved.members[name]
+ if symbol != nil && c.symbolIsValue(symbol) {
+ return symbol
+ }
+ }
+ return nil
+}
+
+func (c *Checker) getPropertyOfUnionOrIntersectionType(t *Type, name string, skipObjectFunctionPropertyAugment bool) *Symbol {
+ return nil // !!!
+}
+
+/**
+ * For a type parameter, return the base constraint of the type parameter. For the string, number,
+ * boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
+ * type itself.
+ */
+func (c *Checker) getApparentType(typ *Type) *Type {
+ return typ
+ // !!!
+ // t := typ
+ // if t.flags&TypeFlagsInstantiable != 0 {
+ // t = c.getBaseConstraintOfType(t)
+ // if t == nil {
+ // t = c.unknownType
+ // }
+ // }
+ // data := t.TypeData()
+ // switch {
+ // case data.objectFlags&ObjectFlagsMapped != 0:
+ // return c.getApparentTypeOfMappedType(t.(*MappedType))
+ // case data.objectFlags&ObjectFlagsReference != 0 && t != typ:
+ // return c.getTypeWithThisArgument(t, typ)
+ // case data.flags&TypeFlagsIntersection != 0:
+ // return c.getApparentTypeOfIntersectionType(t.(*IntersectionType), typ)
+ // case data.flags&TypeFlagsStringLike != 0:
+ // return c.globalStringType
+ // case data.flags&TypeFlagsNumberLike != 0:
+ // return c.globalNumberType
+ // case data.flags&TypeFlagsBigIntLike != 0:
+ // return c.getGlobalBigIntType()
+ // case data.flags&TypeFlagsBooleanLike != 0:
+ // return c.globalBooleanType
+ // case data.flags&TypeFlagsESSymbolLike != 0:
+ // return c.getGlobalESSymbolType()
+ // case data.flags&TypeFlagsNonPrimitive != 0:
+ // return c.emptyObjectType
+ // case data.flags&TypeFlagsIndex != 0:
+ // return c.stringNumberSymbolType
+ // case data.flags&TypeFlagsUnknown != 0 && !c.strictNullChecks:
+ // return c.emptyObjectType
+ // default:
+ // return t
+ // }
+}
+
+func (c *Checker) getReducedType(t *Type) *Type {
+ return t // !!!
+}
+
+func (c *Checker) getReducedApparentType(t *Type) *Type {
+ // Since getApparentType may return a non-reduced union or intersection type, we need to perform
+ // type reduction both before and after obtaining the apparent type. For example, given a type parameter
+ // 'T extends A | B', the type 'T & X' becomes 'A & X | B & X' after obtaining the apparent type, and
+ // that type may need further reduction to remove empty intersections.
+ return c.getReducedType(c.getApparentType(c.getReducedType(t)))
+}
+
+func (c *Checker) getTypeArguments(t *Type) []*Type {
+ d := t.ParameterizedType()
+ if d.resolvedTypeArguments == nil {
+ dt := d.target.InterfaceType()
+ if !c.pushTypeResolution(t, TypeSystemPropertyNameResolvedTypeArguments) {
+ return slices.Repeat([]*Type{c.errorType}, len(dt.outerTypeParameters)+len(dt.localTypeParameters))
+ }
+ var typeArguments []*Type
+ node := t.TypeReference().node
+ if node != nil {
+ switch node.kind {
+ case SyntaxKindTypeReference:
+ typeArguments = concatenate(dt.outerTypeParameters, c.getEffectiveTypeArguments(node.AsTypeReference().typeArguments, dt.localTypeParameters))
+ case SyntaxKindArrayType:
+ typeArguments = []*Type{c.getTypeFromTypeNode(node.AsArrayTypeNode().elementType)}
+ case SyntaxKindTupleType:
+ typeArguments = mapf(node.AsTupleTypeNode().elements, c.getTypeFromTypeNode)
+ default:
+ panic("Unhandled case in getTypeArguments")
+ }
+ }
+ if c.popTypeResolution() {
+ if d.resolvedTypeArguments == nil {
+ d.resolvedTypeArguments = c.instantiateTypes(typeArguments, d.mapper)
+ }
+ } else {
+ if d.resolvedTypeArguments == nil {
+ d.resolvedTypeArguments = slices.Repeat([]*Type{c.errorType}, len(dt.outerTypeParameters)+len(dt.localTypeParameters))
+ }
+ errorNode := ifElse(node != nil, node, c.currentNode)
+ if d.target.symbol != nil {
+ c.error(errorNode, diagnostics.Type_arguments_for_0_circularly_reference_themselves, c.symbolToString(d.target.symbol))
+ } else {
+ c.error(errorNode, diagnostics.Tuple_type_arguments_circularly_reference_themselves)
+ }
+ }
+ }
+ return d.resolvedTypeArguments
+}
+
+func (c *Checker) getEffectiveTypeArguments(node *Node, typeParameters []*Type) []*Type {
+ return c.fillMissingTypeArguments(mapf(node.AsTypeArgumentList().arguments, c.getTypeFromTypeNode), typeParameters, c.getMinTypeArgumentCount(typeParameters))
+}
+
+/**
+ * Gets the minimum number of type arguments needed to satisfy all non-optional type
+ * parameters.
+ */
+func (c *Checker) getMinTypeArgumentCount(typeParameters []*Type) int {
+ minTypeArgumentCount := 0
+ for i, typeParameter := range typeParameters {
+ if !c.hasTypeParameterDefault(typeParameter) {
+ minTypeArgumentCount = i + 1
+ }
+ }
+ return minTypeArgumentCount
+}
+
+func (c *Checker) hasTypeParameterDefault(t *Type) bool {
+ return t.symbol != nil && some(t.symbol.declarations, func(d *Node) bool {
+ return isTypeParameterDeclaration(d) && d.AsTypeParameter().defaultType != nil
+ })
+}
+
+func (c *Checker) fillMissingTypeArguments(typeArguments []*Type, typeParameters []*Type, minTypeArgumentCount int) []*Type {
+ numTypeParameters := len(typeParameters)
+ if numTypeParameters == 0 {
+ return nil
+ }
+ numTypeArguments := len(typeArguments)
+ if numTypeArguments >= minTypeArgumentCount && numTypeArguments < numTypeParameters {
+ result := make([]*Type, numTypeParameters)
+ copy(result, typeArguments)
+ // Map invalid forward references in default types to the error type
+ for i := numTypeArguments; i < numTypeParameters; i++ {
+ result[i] = c.errorType
+ }
+ for i := numTypeArguments; i < numTypeParameters; i++ {
+ defaultType := c.getDefaultFromTypeParameter(typeParameters[i])
+ if defaultType != nil {
+ result[i] = c.instantiateType(defaultType, c.newTypeMapper(typeParameters, result))
+ } else {
+ result[i] = c.unknownType
+ }
+ }
+ return result
+ }
+ return typeArguments
+}
+
+func (c *Checker) getDefaultFromTypeParameter(t *Type) *Type {
+ return c.unknownType // !!!
+}
+
+func (c *Checker) getNamedMembers(members SymbolTable) []*Symbol {
+ var result []*Symbol
+ for id, symbol := range members {
+ if c.isNamedMember(symbol, id) {
+ result = append(result, symbol)
+ }
+ }
+ return result
+}
+
+func (c *Checker) isNamedMember(symbol *Symbol, id string) bool {
+ return !isReservedMemberName(id) && c.symbolIsValue(symbol)
+}
+
+func isReservedMemberName(name string) bool {
+ return len(name) >= 1 && name[0] == 0xFE
+}
+
+func (c *Checker) symbolIsValue(symbol *Symbol) bool {
+ return c.symbolIsValueEx(symbol, false /*includeTyoeOnlyMembers*/)
+}
+
+func (c *Checker) symbolIsValueEx(symbol *Symbol, includeTypeOnlyMembers bool) bool {
+ return symbol.flags&SymbolFlagsValue != 0 || symbol.flags&SymbolFlagsAlias != 0 &&
+ c.getSymbolFlagsEx(symbol, !includeTypeOnlyMembers, false /*excludeLocalMeanings*/)&SymbolFlagsValue != 0
+}
+
+func (c *Checker) instantiateType(t *Type, m TypeMapper) *Type {
+ if m == nil {
+ return t
+ }
+ return t // !!!
+}
+
+func (c *Checker) instantiateTypes(types []*Type, m TypeMapper) []*Type {
+ if m == nil {
+ return types
+ }
+ return types // !!!
+}
+
+func (c *Checker) tryGetTypeFromEffectiveTypeNode(node *Node) *Type {
+ typeNode := getEffectiveTypeAnnotationNode(node)
+ if typeNode != nil {
+ return c.getTypeFromTypeNode(typeNode)
+ }
+ return nil
+}
+
+func (c *Checker) getTypeFromTypeNode(node *Node) *Type {
+ return c.getConditionalFlowTypeOfType(c.getTypeFromTypeNodeWorker(node), node)
+}
+
+func (c *Checker) getTypeFromTypeNodeWorker(node *Node) *Type {
+ switch node.kind {
+ case SyntaxKindAnyKeyword:
+ return c.anyType
+ case SyntaxKindUnknownKeyword:
+ return c.unknownType
+ case SyntaxKindStringKeyword:
+ return c.stringType
+ case SyntaxKindNumberKeyword:
+ return c.numberType
+ case SyntaxKindBigIntKeyword:
+ return c.bigintType
+ case SyntaxKindBooleanKeyword:
+ return c.booleanType
+ case SyntaxKindSymbolKeyword:
+ return c.esSymbolType
+ case SyntaxKindVoidKeyword:
+ return c.voidType
+ case SyntaxKindUndefinedKeyword:
+ return c.undefinedType
+ case SyntaxKindNullKeyword:
+ return c.nullType
+ case SyntaxKindNeverKeyword:
+ return c.neverType
+ case SyntaxKindObjectKeyword:
+ if node.flags&NodeFlagsJavaScriptFile != 0 && !c.noImplicitAny {
+ return c.anyType
+ } else {
+ return c.nonPrimitiveType
+ }
+ case SyntaxKindIntrinsicKeyword:
+ return c.intrinsicMarkerType
+ case SyntaxKindThisType, SyntaxKindThisKeyword:
+ return c.getTypeFromThisTypeNode(node)
+ case SyntaxKindLiteralType:
+ return c.getTypeFromLiteralTypeNode(node)
+ case SyntaxKindTypeReference:
+ return c.getTypeFromTypeReference(node)
+ // case SyntaxKindTypePredicate:
+ // if (node /* as TypePredicateNode */).assertsModifier {
+ // return c.voidType
+ // } else {
+ // return c.booleanType
+ // }
+ // case SyntaxKindExpressionWithTypeArguments:
+ // return c.getTypeFromTypeReference(node /* as ExpressionWithTypeArguments */)
+ // case SyntaxKindTypeQuery:
+ // return c.getTypeFromTypeQueryNode(node /* as TypeQueryNode */)
+ // case SyntaxKindArrayType, SyntaxKindTupleType:
+ // return c.getTypeFromArrayOrTupleTypeNode(node /* as ArrayTypeNode | TupleTypeNode */)
+ // case SyntaxKindOptionalType:
+ // return c.getTypeFromOptionalTypeNode(node /* as OptionalTypeNode */)
+ // case SyntaxKindUnionType:
+ // return c.getTypeFromUnionTypeNode(node /* as UnionTypeNode */)
+ // case SyntaxKindIntersectionType:
+ // return c.getTypeFromIntersectionTypeNode(node /* as IntersectionTypeNode */)
+ // case SyntaxKindNamedTupleMember:
+ // return c.getTypeFromNamedTupleTypeNode(node /* as NamedTupleMember */)
+ // case SyntaxKindParenthesizedType:
+ // return c.getTypeFromTypeNode((node /* as ParenthesizedTypeNode | NamedTupleMember */).type_)
+ // case SyntaxKindRestType:
+ // return c.getTypeFromRestTypeNode(node /* as RestTypeNode */)
+ case SyntaxKindFunctionType, SyntaxKindConstructorType, SyntaxKindTypeLiteral:
+ return c.getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node)
+ // case SyntaxKindTypeOperator:
+ // return c.getTypeFromTypeOperatorNode(node /* as TypeOperatorNode */)
+ // case SyntaxKindIndexedAccessType:
+ // return c.getTypeFromIndexedAccessTypeNode(node /* as IndexedAccessTypeNode */)
+ // case SyntaxKindMappedType:
+ // return c.getTypeFromMappedTypeNode(node /* as MappedTypeNode */)
+ // case SyntaxKindConditionalType:
+ // return c.getTypeFromConditionalTypeNode(node /* as ConditionalTypeNode */)
+ // case SyntaxKindInferType:
+ // return c.getTypeFromInferTypeNode(node /* as InferTypeNode */)
+ // case SyntaxKindTemplateLiteralType:
+ // return c.getTypeFromTemplateTypeNode(node /* as TemplateLiteralTypeNode */)
+ // case SyntaxKindImportType:
+ // return c.getTypeFromImportTypeNode(node /* as ImportTypeNode */)
+ // case SyntaxKindIdentifier, /* as TypeNodeSyntaxKind */
+ // SyntaxKindQualifiedName, /* as TypeNodeSyntaxKind */
+ // SyntaxKindPropertyAccessExpression /* as TypeNodeSyntaxKind */ :
+ // symbol := c.getSymbolAtLocation(node)
+ // if symbol {
+ // return c.getDeclaredTypeOfSymbol(symbol)
+ // } else {
+ // return c.errorType
+ // }
+ default:
+ return c.errorType
+ }
+}
+
+func (c *Checker) getTypeFromThisTypeNode(node *Node) *Type {
+ links := c.nodeLinks.get(node)
+ if links.resolvedType == nil {
+ links.resolvedType = c.getThisType(node)
+ }
+ return links.resolvedType
+}
+
+func (c *Checker) getThisType(node *Node) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) getTypeFromLiteralTypeNode(node *Node) *Type {
+ if node.AsLiteralTypeNode().literal.kind == SyntaxKindNullKeyword {
+ return c.nullType
+ }
+ links := c.nodeLinks.get(node)
+ if links.resolvedType == nil {
+ links.resolvedType = c.getRegularTypeOfLiteralType(c.checkExpression(node.AsLiteralTypeNode().literal))
+ }
+ return links.resolvedType
+}
+
+func (c *Checker) getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node *Node) *Type {
+ links := c.nodeLinks.get(node)
+ if links.resolvedType == nil {
+ // Deferred resolution of members is handled by resolveObjectTypeMembers
+ alias := c.getAliasForTypeNode(node)
+ if len(c.getMembersOfSymbol(node.Symbol())) == 0 && alias == nil {
+ links.resolvedType = c.emptyTypeLiteralType
+ } else {
+ t := c.newObjectType(ObjectFlagsAnonymous, node.Symbol())
+ t.alias = alias
+ links.resolvedType = t
+ }
+ }
+ return links.resolvedType
+}
+
+func (c *Checker) getTypeFromTypeReference(node *Node) *Type {
+ links := c.nodeLinks.get(node)
+ if links.resolvedType == nil {
+ // handle LS queries on the `const` in `x as const` by resolving to the type of `x`
+ if isConstTypeReference(node) && isAssertionExpression(node.parent) {
+ links.resolvedSymbol = c.unknownSymbol
+ links.resolvedType = c.checkExpressionCached(getAccessedExpression(node.parent))
+ return links.resolvedType
+ }
+ symbol := c.resolveTypeReferenceName(node, SymbolFlagsType, false /*ignoreErrors*/)
+ t := c.getTypeReferenceType(node, symbol)
+ // Cache both the resolved symbol and the resolved type. The resolved symbol is needed when we check the
+ // type reference in checkTypeReferenceNode.
+ links.resolvedSymbol = symbol
+ links.resolvedType = t
+ }
+ return links.resolvedType
+}
+
+func (c *Checker) resolveTypeReferenceName(typeReference *Node, meaning SymbolFlags, ignoreErrors bool) *Symbol {
+ name := getTypeReferenceName(typeReference)
+ if name == nil {
+ return c.unknownSymbol
+ }
+ symbol := c.resolveEntityName(name, meaning, ignoreErrors, false /*dontResolveAlias*/, nil /*location*/)
+ if symbol != nil && symbol != c.unknownSymbol {
+ return symbol
+ }
+ if ignoreErrors {
+ return c.unknownSymbol
+ }
+ return c.unknownSymbol // !!! return c.getUnresolvedSymbolForEntityName(name)
+}
+
+func (c *Checker) getTypeReferenceType(node *Node, symbol *Symbol) *Type {
+ if symbol == c.unknownSymbol {
+ return c.errorType
+ }
+ if symbol.flags&(SymbolFlagsClass|SymbolFlagsInterface) != 0 {
+ return c.getTypeFromClassOrInterfaceReference(node, symbol)
+ }
+ if symbol.flags&SymbolFlagsTypeAlias != 0 {
+ return c.getTypeFromTypeAliasReference(node, symbol)
+ }
+ // Get type from reference to named type that cannot be generic (enum or type parameter)
+ res := c.tryGetDeclaredTypeOfSymbol(symbol)
+ if res != nil && c.checkNoTypeArguments(node, symbol) {
+ return c.getRegularTypeOfLiteralType(res)
+ }
+ return c.errorType
+}
+
+/**
+ * Get type from type-reference that reference to class or interface
+ */
+func (c *Checker) getTypeFromClassOrInterfaceReference(node *Node, symbol *Symbol) *Type {
+ t := c.getDeclaredTypeOfClassOrInterface(c.getMergedSymbol(symbol))
+ d := t.InterfaceType()
+ typeParameters := d.localTypeParameters
+ if len(typeParameters) != 0 {
+ typeArgumentNodes := c.getTypeArgumentsFromNode(node)
+ numTypeArguments := len(typeArgumentNodes)
+ minTypeArgumentCount := c.getMinTypeArgumentCount(typeParameters)
+ if numTypeArguments < minTypeArgumentCount || numTypeArguments > len(typeParameters) {
+ message := diagnostics.Generic_type_0_requires_1_type_argument_s
+ if minTypeArgumentCount < len(typeParameters) {
+ message = diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments
+ }
+ typeStr := c.typeToString(t) // !!! /*enclosingDeclaration*/, nil, TypeFormatFlagsWriteArrayAsGenericType
+ c.error(node, message, typeStr, minTypeArgumentCount, len(typeParameters))
+ // TODO: Adopt same permissive behavior in TS as in JS to reduce follow-on editing experience failures (requires editing fillMissingTypeArguments)
+ return c.errorType
+ }
+ if node.kind == SyntaxKindTypeReference && c.isDeferredTypeReferenceNode(node, numTypeArguments != len(typeParameters)) {
+ return c.createDeferredTypeReference(t, node, nil /*mapper*/, nil /*alias*/)
+ }
+ // In a type reference, the outer type parameters of the referenced class or interface are automatically
+ // supplied as type arguments and the type reference only specifies arguments for the local type parameters
+ // of the class or interface.
+ localTypeArguments := c.fillMissingTypeArguments(mapf(typeArgumentNodes, c.getTypeFromTypeNode), typeParameters, minTypeArgumentCount)
+ typeArguments := concatenate(d.outerTypeParameters, localTypeArguments)
+ return c.createTypeReference(t, typeArguments)
+ }
+ if c.checkNoTypeArguments(node, symbol) {
+ return t
+ }
+ return c.errorType
+}
+
+func (c *Checker) getTypeArgumentsFromNode(node *Node) []*Node {
+ typeArgumentList := c.getTypeArgumentListFromNode(node)
+ if typeArgumentList != nil {
+ return typeArgumentList.AsTypeArgumentList().arguments
+ }
+ return nil
+}
+
+func (c *Checker) getTypeArgumentListFromNode(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindTypeReference:
+ return node.AsTypeReference().typeArguments
+ case SyntaxKindExpressionWithTypeArguments:
+ return node.AsExpressionWithTypeArguments().typeArguments
+ case SyntaxKindImportType:
+ return node.AsImportTypeNode().typeArguments
+ }
+ panic("Unhandled case in getTypeArgumentListFromNode")
+}
+
+func (c *Checker) checkNoTypeArguments(node *Node, symbol *Symbol) bool {
+ if len(c.getTypeArgumentsFromNode(node)) != 0 {
+ c.error(node, diagnostics.Type_0_is_not_generic, c.symbolToString(symbol))
+ return false
+ }
+ return true
+}
+
+func (c *Checker) isDeferredTypeReferenceNode(node *Node, hasDefaultTypeArguments bool) bool {
+ return false // !!!
+}
+
+func (c *Checker) getTypeFromTypeAliasReference(node *Node, symbol *Symbol) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) getDeclaredTypeOfSymbol(symbol *Symbol) *Type {
+ result := c.tryGetDeclaredTypeOfSymbol(symbol)
+ if result == nil {
+ result = c.errorType
+ }
+ return result
+}
+
+func (c *Checker) tryGetDeclaredTypeOfSymbol(symbol *Symbol) *Type {
+ switch {
+ case symbol.flags&(SymbolFlagsClass|SymbolFlagsInterface) != 0:
+ return c.getDeclaredTypeOfClassOrInterface(symbol)
+ case symbol.flags&SymbolFlagsTypeParameter != 0:
+ return c.getDeclaredTypeOfTypeParameter(symbol)
+ // !!!
+ // case symbol.flags&SymbolFlagsTypeAlias != 0:
+ // return c.getDeclaredTypeOfTypeAlias(symbol)
+ // case symbol.flags&SymbolFlagsEnum != 0:
+ // return c.getDeclaredTypeOfEnum(symbol)
+ // case symbol.flags&SymbolFlagsEnumMember != 0:
+ // return c.getDeclaredTypeOfEnumMember(symbol)
+ // case symbol.flags&SymbolFlagsAlias != 0:
+ // return c.getDeclaredTypeOfAlias(symbol)
+ }
+ return nil
+}
+
+func getTypeReferenceName(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindTypeReference:
+ return node.AsTypeReference().typeName
+ case SyntaxKindExpressionWithTypeArguments:
+ // We only support expressions that are simple qualified names. For other
+ // expressions this produces nil
+ expr := node.AsExpressionWithTypeArguments().expression
+ if isEntityNameExpression(expr) {
+ return expr
+ }
+ }
+ return nil
+}
+
+func (c *Checker) getAliasForTypeNode(node *Node) *TypeAlias {
+ symbol := c.getAliasSymbolForTypeNode(node)
+ if symbol != nil {
+ return &TypeAlias{symbol: symbol, typeArguments: c.getTypeArgumentsForAliasSymbol(symbol)}
+ }
+ return nil
+}
+
+func (c *Checker) getAliasSymbolForTypeNode(node *Node) *Symbol {
+ host := node.parent
+ for isParenthesizedTypeNode(host) || isTypeOperatorNode(host) && host.AsTypeOperatorNode().operator == SyntaxKindReadonlyKeyword {
+ host = host.parent
+ }
+ if isTypeAlias(host) {
+ return c.getSymbolOfDeclaration(host)
+ }
+ return nil
+}
+
+func (c *Checker) getTypeArgumentsForAliasSymbol(symbol *Symbol) []*Type {
+ if symbol != nil {
+ return c.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)
+ }
+ return nil
+}
+
+func (c *Checker) getOuterTypeParametersOfClassOrInterface(symbol *Symbol) []*Type {
+ return nil // !!!
+}
+
+// The local type parameters are the combined set of type parameters from all declarations of the class,
+// interface, or type alias.
+func (c *Checker) getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol *Symbol) []*Type {
+ var result []*Type
+ for _, node := range symbol.declarations {
+ if nodeKindIs(node, SyntaxKindInterfaceDeclaration, SyntaxKindClassDeclaration, SyntaxKindClassExpression) || isTypeAlias(node) {
+ result = c.appendTypeParameters(result, getEffectiveTypeParameterDeclarations(node))
+ }
+ }
+ return result
+}
+
+// Appends the type parameters given by a list of declarations to a set of type parameters and returns the resulting set.
+// The function allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set
+// in-place and returns the same array.
+func (c *Checker) appendTypeParameters(typeParameters []*Type, declarations []*Node) []*Type {
+ for _, declaration := range declarations {
+ typeParameters = appendIfUnique(typeParameters, c.getDeclaredTypeOfTypeParameter(c.getSymbolOfDeclaration(declaration)))
+ }
+ return typeParameters
+}
+
+func (c *Checker) getDeclaredTypeOfTypeParameter(symbol *Symbol) *Type {
+ links := c.typeParameterLinks.get(symbol)
+ if links.declaredType == nil {
+ links.declaredType = c.newTypeParameter(symbol)
+ }
+ return links.declaredType
+}
+
+func (c *Checker) getConditionalFlowTypeOfType(typ *Type, node *Node) *Type {
+ return typ // !!!
+}
+
+func (c *Checker) newType(flags TypeFlags, objectFlags ObjectFlags, data TypeData) *Type {
+ t := &Type{}
+ c.typeCount++
+ t.flags = flags
+ t.objectFlags = objectFlags
+ t.id = TypeId(c.typeCount)
+ t.data = data
+ return t
+}
+
+func (c *Checker) newIntrinsicType(flags TypeFlags, intrinsicName string) *Type {
+ return c.newIntrinsicTypeEx(flags, intrinsicName, ObjectFlagsNone)
+}
+
+func (c *Checker) newIntrinsicTypeEx(flags TypeFlags, intrinsicName string, objectFlags ObjectFlags) *Type {
+ data := &IntrinsicTypeData{}
+ data.intrinsicName = intrinsicName
+ return c.newType(flags, objectFlags, data)
+}
+
+func (c *Checker) createWideningType(nonWideningType *Type) *Type {
+ if c.strictNullChecks {
+ return nonWideningType
+ }
+ return c.newIntrinsicType(nonWideningType.flags, nonWideningType.IntrinsicType().intrinsicName)
+}
+
+func (c *Checker) newLiteralType(flags TypeFlags, value any, regularType *Type) *Type {
+ data := &LiteralTypeData{}
+ data.value = value
+ t := c.newType(flags, ObjectFlagsNone, data)
+ if regularType != nil {
+ data.regularType = regularType
+ } else {
+ data.regularType = t
+ }
+ return t
+}
+
+func (c *Checker) newObjectType(objectFlags ObjectFlags, symbol *Symbol) *Type {
+ t := c.newType(TypeFlagsObject, objectFlags, &AnonymousTypeData{})
+ t.symbol = symbol
+ return t
+}
+
+func (c *Checker) newAnonymousType(symbol *Symbol, members SymbolTable, callSignatures []*Signature, constructSignatures []*Signature, indexInfos []*IndexInfo) *Type {
+ t := c.newObjectType(ObjectFlagsAnonymous, symbol)
+ c.setStructuredTypeMembers(t, members, callSignatures, constructSignatures, indexInfos)
+ return t
+}
+
+func (c *Checker) setStructuredTypeMembers(t *Type, members SymbolTable, callSignatures []*Signature, constructSignatures []*Signature, indexInfos []*IndexInfo) {
+ t.objectFlags |= ObjectFlagsMembersResolved
+ data := t.ObjectType()
+ data.members = members
+ data.properties = c.getNamedMembers(members)
+ data.callSignatures = callSignatures
+ data.constructSignatures = constructSignatures
+ data.indexInfos = indexInfos
+}
+
+func (c *Checker) newInterfaceType(objectFlags ObjectFlags, symbol *Symbol) *Type {
+ t := c.newType(TypeFlagsObject, objectFlags, &InterfaceTypeData{})
+ t.symbol = symbol
+ return t
+}
+
+func (c *Checker) newTypeParameter(symbol *Symbol) *Type {
+ t := c.newType(TypeFlagsTypeParameter, ObjectFlagsNone, &TypeParameterData{})
+ t.symbol = symbol
+ return t
+}
+
+func (c *Checker) newTypeReference(target *Type) *Type {
+ data := &TypeReferenceData{}
+ data.target = target
+ t := c.newType(TypeFlagsObject, ObjectFlagsReference, data)
+ t.symbol = target.symbol
+ return t
+}
+
+func (c *Checker) createTypeReference(target *Type, typeArguments []*Type) *Type {
+ id := getTypeListId(typeArguments)
+ dt := target.InterfaceType()
+ if t, ok := dt.instantiations[id]; ok {
+ return t
+ }
+ t := c.newTypeReference(target)
+ t.objectFlags |= c.getPropagatingFlagsOfTypes(typeArguments, TypeFlagsNone)
+ t.TypeReference().resolvedTypeArguments = typeArguments
+ dt.instantiations[id] = t
+ return t
+}
+
+func (c *Checker) createDeferredTypeReference(target *Type, node *Node, mapper TypeMapper, alias *TypeAlias) *Type {
+ if alias == nil {
+ alias := c.getAliasForTypeNode(node)
+ if mapper != nil {
+ alias.typeArguments = c.instantiateTypes(alias.typeArguments, mapper)
+ }
+ }
+ t := c.newTypeReference(target)
+ t.alias = alias
+ data := t.TypeReference()
+ data.mapper = mapper
+ data.node = node
+ return t
+}
+
+// This function is used to propagate certain flags when creating new object type references and union types.
+// It is only necessary to do so if a constituent type might be the undefined type, the null type, the type
+// of an object literal or a non-inferrable type. This is because there are operations in the type checker
+// that care about the presence of such types at arbitrary depth in a containing type.
+func (c *Checker) getPropagatingFlagsOfTypes(types []*Type, excludeKinds TypeFlags) ObjectFlags {
+ result := ObjectFlagsNone
+ for _, t := range types {
+ if t.flags&excludeKinds == 0 {
+ result |= t.objectFlags
+ }
+ }
+ return result & ObjectFlagsPropagatingFlags
+}
+
+func (c *Checker) newUnionType(objectFlags ObjectFlags, types []*Type) *Type {
+ data := &UnionTypeData{}
+ data.types = types
+ return c.newType(TypeFlagsUnion, objectFlags, data)
+}
+
+func (c *Checker) getRegularTypeOfLiteralType(t *Type) *Type {
+ if t.flags&TypeFlagsFreshable != 0 {
+ return t.LiteralType().regularType
+ }
+ if t.flags&TypeFlagsUnion != 0 {
+ u := t.UnionType()
+ if u.regularType == nil {
+ u.regularType = c.mapType(t, c.getRegularTypeOfLiteralType)
+ }
+ return u.regularType
+ }
+ return t
+}
+
+func (c *Checker) getFreshTypeOfLiteralType(t *Type) *Type {
+ if data, ok := t.data.(*LiteralTypeData); ok {
+ if data.freshType == nil {
+ f := c.newLiteralType(t.flags, data.value, t)
+ f.LiteralType().freshType = f
+ data.freshType = f
+ }
+ return data.freshType
+ }
+ return t
+}
+
+func (c *Checker) getStringLiteralType(value string) *Type {
+ t := c.stringLiteralTypes[value]
+ if t == nil {
+ t = c.newLiteralType(TypeFlagsStringLiteral, value, nil)
+ c.stringLiteralTypes[value] = t
+ }
+ return t
+}
+
+func (c *Checker) getNumberLiteralType(value float64) *Type {
+ t := c.numberLiteralTypes[value]
+ if t == nil {
+ t = c.newLiteralType(TypeFlagsNumberLiteral, value, nil)
+ c.numberLiteralTypes[value] = t
+ }
+ return t
+}
+
+func (c *Checker) getBigintLiteralType(value PseudoBigint) *Type {
+ t := c.bigintLiteralTypes[value]
+ if t == nil {
+ t = c.newLiteralType(TypeFlagsBigintLiteral, value, nil)
+ c.bigintLiteralTypes[value] = t
+ }
+ return t
+}
+
+func (c *Checker) getEnumLiteralType(value any, enumSymbol *Symbol, symbol *Symbol) *Type {
+ var flags TypeFlags
+ switch value.(type) {
+ case string:
+ flags = TypeFlagsEnumLiteral | TypeFlagsStringLiteral
+ case float64:
+ flags = TypeFlagsEnumLiteral | TypeFlagsNumberLiteral
+ default:
+ panic("Unhandled case in getEnumLiteralType")
+ }
+ key := EnumLiteralKey{enumSymbol: enumSymbol, value: value}
+ t := c.enumLiteralTypes[key]
+ if t == nil {
+ t = c.newLiteralType(flags, value, nil)
+ t.symbol = symbol
+ c.enumLiteralTypes[key] = t
+ }
+ return t
+}
+
+func (c *Checker) getBaseTypeOfLiteralType(t *Type) *Type {
+ switch {
+ case t.flags&TypeFlagsEnumLike != 0:
+ return c.getBaseTypeOfEnumLikeType(t)
+ case t.flags&(TypeFlagsStringLiteral|TypeFlagsTemplateLiteral|TypeFlagsStringMapping) != 0:
+ return c.stringType
+ case t.flags&TypeFlagsNumberLiteral != 0:
+ return c.numberType
+ case t.flags&TypeFlagsBigintLiteral != 0:
+ return c.bigintType
+ case t.flags&TypeFlagsBooleanLiteral != 0:
+ return c.booleanType
+ case t.flags&TypeFlagsUnion != 0:
+ return c.getBaseTypeOfLiteralTypeUnion(t)
+ }
+ return t
+}
+
+func (c *Checker) getBaseTypeOfEnumLikeType(t *Type) *Type {
+ if t.flags&TypeFlagsEnumLike != 0 && t.symbol.flags&SymbolFlagsEnumMember != 0 {
+ return c.getDeclaredTypeOfSymbol(c.getParentOfSymbol(t.symbol))
+ }
+ return t
+}
+
+func (c *Checker) getBaseTypeOfLiteralTypeUnion(t *Type) *Type {
+ key := CachedTypeKey{kind: CachedTypeKindLiteralUnionBaseType, typeId: t.id}
+ if cached, ok := c.cachedTypes[key]; ok {
+ return cached
+ }
+ result := c.mapType(t, c.getBaseTypeOfLiteralType)
+ c.cachedTypes[key] = result
+ return result
+}
+
+func (c *Checker) getWidenedLiteralType(t *Type) *Type {
+ switch {
+ case t.flags&TypeFlagsEnumLike != 0 && isFreshLiteralType(t):
+ return c.getBaseTypeOfEnumLikeType(t)
+ case t.flags&TypeFlagsStringLiteral != 0 && isFreshLiteralType(t):
+ return c.stringType
+ case t.flags&TypeFlagsNumberLiteral != 0 && isFreshLiteralType(t):
+ return c.numberType
+ case t.flags&TypeFlagsBigintLiteral != 0 && isFreshLiteralType(t):
+ return c.bigintType
+ case t.flags&TypeFlagsBooleanLiteral != 0 && isFreshLiteralType(t):
+ return c.booleanType
+ case t.flags&TypeFlagsUnion != 0:
+ return c.mapType(t, c.getWidenedLiteralType)
+ }
+ return t
+}
+
+func (c *Checker) getWidenedUniqueESSymbolType(t *Type) *Type {
+ switch {
+ case t.flags&TypeFlagsUniqueESSymbol != 0:
+ return c.esSymbolType
+ case t.flags&TypeFlagsUnion != 0:
+ return c.mapType(t, c.getWidenedUniqueESSymbolType)
+ }
+ return t
+}
+
+func (c *Checker) mapType(t *Type, f func(*Type) *Type) *Type {
+ return c.mapTypeEx(t, f, false /*noReductions*/)
+}
+
+func (c *Checker) mapTypeEx(t *Type, f func(*Type) *Type, noReductions bool) *Type {
+ if t.flags&TypeFlagsNever != 0 {
+ return t
+ }
+ if t.flags&TypeFlagsUnion == 0 {
+ return f(t)
+ }
+ u := t.UnionType()
+ types := u.types
+ if u.origin != nil && u.origin.flags&TypeFlagsUnion != 0 {
+ types = u.origin.UnionType().types
+ }
+ var mappedTypes []*Type
+ var changed bool
+ for _, s := range types {
+ var mapped *Type
+ if s.flags&TypeFlagsUnion != 0 {
+ mapped = c.mapTypeEx(s, f, noReductions)
+ } else {
+ mapped = f(s)
+ }
+ if mapped != s {
+ changed = true
+ }
+ if mapped != nil {
+ mappedTypes = append(mappedTypes, mapped)
+ }
+ }
+ if changed {
+ unionReduction := UnionReductionLiteral
+ if noReductions {
+ unionReduction = UnionReductionNone
+ }
+ return c.getUnionTypeEx(mappedTypes, unionReduction, nil /*alias*/, nil /*origin*/)
+ }
+ return t
+}
+
+type UnionReduction int32
+
+const (
+ UnionReductionNone UnionReduction = iota
+ UnionReductionLiteral
+ UnionReductionSubtype
+)
+
+func (c *Checker) getUnionType(types []*Type) *Type {
+ return c.getUnionTypeEx(types, UnionReductionLiteral, nil /*alias*/, nil /*origin*/)
+}
+
+// We sort and deduplicate the constituent types based on object identity. If the subtypeReduction
+// flag is specified we also reduce the constituent type set to only include types that aren't subtypes
+// of other types. Subtype reduction is expensive for large union types and is possible only when union
+// types are known not to circularly reference themselves (as is the case with union types created by
+// expression constructs such as array literals and the || and ?: operators). Named types can
+// circularly reference themselves and therefore cannot be subtype reduced during their declaration.
+// For example, "type Item = string | (() => Item" is a named type that circularly references itself.
+func (c *Checker) getUnionTypeEx(types []*Type, unionReduction UnionReduction, alias *TypeAlias, origin *Type) *Type {
+ if len(types) == 0 {
+ return c.neverType
+ }
+ if len(types) == 1 {
+ return types[0]
+ }
+ // We optimize for the common case of unioning a union type with some other type (such as `undefined`).
+ if len(types) == 2 && origin == nil && (types[0].flags&TypeFlagsUnion != 0 || types[1].flags&TypeFlagsUnion != 0) {
+ id1 := types[0].id
+ id2 := types[1].id
+ if id1 > id2 {
+ id1, id2 = id2, id1
+ }
+ key := UnionOfUnionKey{id1: id1, id2: id2, r: unionReduction, a: getAliasId(alias)}
+ t := c.unionOfUnionTypes[key]
+ if t == nil {
+ t = c.getUnionTypeWorker(types, unionReduction, alias, nil /*origin*/)
+ c.unionOfUnionTypes[key] = t
+ }
+ return t
+ }
+ return c.getUnionTypeWorker(types, unionReduction, alias, origin)
+}
+
+func (c *Checker) getUnionTypeWorker(types []*Type, unionReduction UnionReduction, alias *TypeAlias, origin *Type) *Type {
+ typeSet, includes := c.addTypesToUnion(nil, 0, types)
+ if unionReduction != UnionReductionNone {
+ if includes&TypeFlagsAnyOrUnknown != 0 {
+ if includes&TypeFlagsAny != 0 {
+ switch {
+ case includes&TypeFlagsIncludesWildcard != 0:
+ return c.wildcardType
+ case includes&TypeFlagsIncludesError != 0:
+ return c.errorType
+ }
+ return c.anyType
+ }
+ return c.unknownType
+ }
+ if includes&TypeFlagsUndefined != 0 {
+ // If type set contains both undefinedType and missingType, remove missingType
+ if len(typeSet) >= 2 && typeSet[0] == c.undefinedType && typeSet[1] == c.missingType {
+ typeSet = slices.Delete(typeSet, 1, 2)
+ }
+ }
+ if includes&(TypeFlagsEnum|TypeFlagsLiteral|TypeFlagsUniqueESSymbol|TypeFlagsTemplateLiteral|TypeFlagsStringMapping) != 0 ||
+ includes&TypeFlagsVoid != 0 && includes&TypeFlagsUndefined != 0 {
+ c.removeRedundantLiteralTypes(typeSet, includes, unionReduction&UnionReductionSubtype != 0)
+ }
+ if includes&TypeFlagsStringLiteral != 0 && includes&(TypeFlagsTemplateLiteral|TypeFlagsStringMapping) != 0 {
+ c.removeStringLiteralsMatchedByTemplateLiterals(typeSet)
+ }
+ if includes&TypeFlagsIncludesConstrainedTypeVariable != 0 {
+ c.removeConstrainedTypeVariables(typeSet)
+ }
+ if unionReduction == UnionReductionSubtype {
+ typeSet = c.removeSubtypes(typeSet, includes&TypeFlagsObject != 0)
+ if typeSet == nil {
+ return c.errorType
+ }
+ }
+ if len(typeSet) == 0 {
+ switch {
+ case includes&TypeFlagsNull != 0:
+ if includes&TypeFlagsIncludesNonWideningType != 0 {
+ return c.nullType
+ }
+ return c.nullWideningType
+ case includes&TypeFlagsUndefined != 0:
+ if includes&TypeFlagsIncludesNonWideningType != 0 {
+ return c.undefinedType
+ }
+ return c.undefinedWideningType
+ }
+ return c.neverType
+ }
+ }
+ if origin == nil && includes&TypeFlagsUnion != 0 {
+ namedUnions := c.addNamedUnions(nil, types)
+ var reducedTypes []*Type
+ for _, t := range typeSet {
+ if !some(namedUnions, func(u *Type) bool { return containsType(u.UnionType().types, t) }) {
+ reducedTypes = append(reducedTypes, t)
+ }
+ }
+ if alias == nil && len(namedUnions) == 1 && len(reducedTypes) == 0 {
+ return namedUnions[0]
+ }
+ // We create a denormalized origin type only when the union was created from one or more named unions
+ // (unions with alias symbols or origins) and when there is no overlap between those named unions.
+ namedTypesCount := 0
+ for _, u := range namedUnions {
+ namedTypesCount += len(u.UnionType().types)
+ }
+ if namedTypesCount+len(reducedTypes) == len(typeSet) {
+ for _, t := range namedUnions {
+ reducedTypes = insertType(reducedTypes, t)
+ }
+ // !!! Properly handle union vs. intersection origin
+ origin = c.newUnionType(ObjectFlagsNone, reducedTypes)
+ }
+ }
+ objectFlags := ifElse(includes&TypeFlagsNotPrimitiveUnion != 0, ObjectFlagsNone, ObjectFlagsPrimitiveUnion) |
+ ifElse(includes&TypeFlagsIntersection != 0, ObjectFlagsContainsIntersections, ObjectFlagsNone)
+ return c.getUnionTypeFromSortedList(typeSet, objectFlags, alias, origin)
+}
+
+// This function assumes the constituent type list is sorted and deduplicated.
+func (c *Checker) getUnionTypeFromSortedList(types []*Type, precomputedObjectFlags ObjectFlags, alias *TypeAlias, origin *Type) *Type {
+ if len(types) == 0 {
+ return c.neverType
+ }
+ if len(types) == 1 {
+ return types[0]
+ }
+ key := getUnionId(types, origin, alias)
+ t := c.unionTypes[key]
+ if t == nil {
+ t = c.newUnionType(precomputedObjectFlags|c.getPropagatingFlagsOfTypes(types, TypeFlagsNullable), types)
+ t.UnionType().origin = origin
+ t.alias = alias
+ if len(types) == 2 && types[0].flags&TypeFlagsBooleanLiteral != 0 && types[1].flags&TypeFlagsBooleanLiteral != 0 {
+ t.flags |= TypeFlagsBoolean
+ }
+ c.unionTypes[key] = t
+ }
+ return t
+}
+
+func (c *Checker) addTypesToUnion(typeSet []*Type, includes TypeFlags, types []*Type) ([]*Type, TypeFlags) {
+ var lastType *Type
+ for _, t := range types {
+ if t != lastType {
+ if t.flags&TypeFlagsUnion != 0 {
+ u := t.UnionType()
+ if t.alias != nil || u.origin != nil {
+ includes |= TypeFlagsUnion
+ }
+ typeSet, includes = c.addTypesToUnion(typeSet, includes, u.types)
+ } else {
+ typeSet, includes = c.addTypeToUnion(typeSet, includes, t)
+ }
+ lastType = t
+ }
+ }
+ return typeSet, includes
+}
+
+func (c *Checker) addTypeToUnion(typeSet []*Type, includes TypeFlags, t *Type) ([]*Type, TypeFlags) {
+ flags := t.flags
+ // We ignore 'never' types in unions
+ if flags&TypeFlagsNever == 0 {
+ includes |= flags & TypeFlagsIncludesMask
+ if flags&TypeFlagsInstantiable != 0 {
+ includes |= TypeFlagsIncludesInstantiable
+ }
+ if flags&TypeFlagsIntersection != 0 && t.objectFlags&ObjectFlagsIsConstrainedTypeVariable != 0 {
+ includes |= TypeFlagsIncludesConstrainedTypeVariable
+ }
+ if t == c.wildcardType {
+ includes |= TypeFlagsIncludesWildcard
+ }
+ if c.isErrorType(t) {
+ includes |= TypeFlagsIncludesError
+ }
+ if !c.strictNullChecks && flags&TypeFlagsNullable != 0 {
+ if t.objectFlags&ObjectFlagsContainsWideningType == 0 {
+ includes |= TypeFlagsIncludesNonWideningType
+ }
+ } else {
+ var index int
+ var ok bool
+ if len(typeSet) != 0 && t.id > typeSet[len(typeSet)-1].id {
+ index = len(typeSet)
+ } else {
+ index, ok = slices.BinarySearchFunc(typeSet, t, compareTypeIds)
+ }
+ if !ok {
+ typeSet = slices.Insert(typeSet, index, t)
+ }
+ }
+ }
+ return typeSet, includes
+}
+
+func (c *Checker) addNamedUnions(namedUnions []*Type, types []*Type) []*Type {
+ for _, t := range types {
+ if t.flags&TypeFlagsUnion != 0 {
+ u := t.UnionType()
+ if t.alias != nil || u.origin != nil && u.origin.flags&TypeFlagsUnion == 0 {
+ namedUnions = appendIfUnique(namedUnions, t)
+ } else if u.origin != nil && u.origin.flags&TypeFlagsUnion != 0 {
+ namedUnions = c.addNamedUnions(namedUnions, u.origin.UnionType().types)
+ }
+ }
+ }
+ return namedUnions
+}
+
+func (c *Checker) removeRedundantLiteralTypes(types []*Type, includes TypeFlags, reduceVoidUndefined bool) {
+ // !!!
+}
+
+func (c *Checker) removeStringLiteralsMatchedByTemplateLiterals(types []*Type) {
+ // !!!
+}
+
+func (c *Checker) removeConstrainedTypeVariables(types []*Type) {
+ // !!!
+}
+
+func (c *Checker) removeSubtypes(types []*Type, hasObjectTypes bool) []*Type {
+ // !!!
+ return types
+}
+
+func containsType(types []*Type, t *Type) bool {
+ _, ok := slices.BinarySearchFunc(types, t, compareTypeIds)
+ return ok
+}
+
+func insertType(types []*Type, t *Type) []*Type {
+ if i, ok := slices.BinarySearchFunc(types, t, compareTypeIds); !ok {
+ return slices.Insert(types, i, t)
+ }
+ return types
+}
+
+func (c *Checker) isErrorType(t *Type) bool {
+ // The only 'any' types that have alias symbols are those manufactured by getTypeFromTypeAliasReference for
+ // a reference to an unresolved symbol. We want those to behave like the errorType.
+ return t == c.errorType || t.flags&TypeFlagsAny != 0 && t.alias != nil
+}
+
+func compareTypeIds(t1, t2 *Type) int {
+ return int(t1.id) - int(t2.id)
+}
+
+func (c *Checker) getIntersectionType(types ...*Type) *Type {
+ return c.anyType // !!!
+}
+
+func (c *Checker) newTypeMapper(sources []*Type, targets []*Type) TypeMapper {
+ if len(sources) == 1 {
+ return &SimpleTypeMapper{source: sources[0], target: ifElse(targets != nil, targets[0], c.anyType)}
+ }
+ return &ArrayTypeMapper{sources: sources, targets: targets}
+}
+
+// SimpleTypeMapper
+
+type SimpleTypeMapper struct {
+ source *Type
+ target *Type
+}
+
+func (m *SimpleTypeMapper) Map(t *Type) *Type {
+ if t == m.source {
+ return m.target
+ }
+ return t
+}
+
+// ArrayTypeMapper
+
+type ArrayTypeMapper struct {
+ sources []*Type
+ targets []*Type
+}
+
+func (m *ArrayTypeMapper) Map(t *Type) *Type {
+ for i, s := range m.sources {
+ if t == s {
+ return m.targets[i]
+ }
+ }
+ return t
+}
+
+// ArrayToSingleTypeMapper
+
+type ArrayToSingleTypeMapper struct {
+ sources []*Type
+ target *Type
+}
+
+func (m *ArrayToSingleTypeMapper) Map(t *Type) *Type {
+ for _, s := range m.sources {
+ if t == s {
+ return m.target
+ }
+ }
+ return t
+}
+
+// DeferredTypeMapper
+
+type DeferredTypeMapper struct {
+ sources []*Type
+ targets []func() *Type
+}
+
+func (m *DeferredTypeMapper) Map(t *Type) *Type {
+ for i, s := range m.sources {
+ if t == s {
+ return m.targets[i]()
+ }
+ }
+ return t
+}
+
+// FunctionTypeMapper
+
+type FunctionTypeMapper struct {
+ fn func(*Type) *Type
+}
+
+func (m *FunctionTypeMapper) Map(t *Type) *Type {
+ return m.fn(t)
+}
+
+// MergedTypeMapper
+
+type MergedTypeMapper struct {
+ m1 TypeMapper
+ m2 TypeMapper
+}
+
+func (m *MergedTypeMapper) Map(t *Type) *Type {
+ return m.m2.Map(m.m1.Map(t))
+}
+
+// CompositeTypeMapper
+
+type CompositeTypeMapper struct {
+ c *Checker
+ m1 TypeMapper
+ m2 TypeMapper
+}
+
+func (m *CompositeTypeMapper) Map(t *Type) *Type {
+ t1 := m.m1.Map(t)
+ if t1 != t {
+ return m.c.instantiateType(t1, m.m2)
+ }
+ return m.m2.Map(t)
+}
diff --git a/internal/compiler/host.go b/internal/compiler/host.go
new file mode 100644
index 0000000000..16eed46ae2
--- /dev/null
+++ b/internal/compiler/host.go
@@ -0,0 +1,116 @@
+package compiler
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "io/fs"
+ "os"
+ "path/filepath"
+ "slices"
+ "strings"
+ "sync"
+ "unicode/utf16"
+)
+
+type CompilerHost interface {
+ ReadFile(fileName string) (text string, ok bool)
+ ReadDirectory(rootPath string, extensions []string) []FileInfo
+ AbsFileName(fileName string) string
+ RunTask(func())
+ WaitForTasks()
+}
+
+type FileInfo struct {
+ Name string
+ Size int64
+}
+
+type compilerHost struct {
+ options *CompilerOptions
+ singleThreaded bool
+ wg sync.WaitGroup
+ readSema chan struct{}
+}
+
+func NewCompilerHost(options *CompilerOptions, singleThreaded bool) CompilerHost {
+ h := &compilerHost{}
+ h.options = options
+ h.singleThreaded = singleThreaded
+ h.readSema = make(chan struct{}, 128)
+ return h
+}
+
+func (h *compilerHost) ReadFile(fileName string) (text string, ok bool) {
+ h.readSema <- struct{}{}
+ b, err := os.ReadFile(fileName)
+ <-h.readSema
+ if err != nil {
+ return "", false
+ }
+ var bom [2]byte
+ if len(b) >= 2 {
+ bom = [2]byte{b[0], b[1]}
+ switch bom {
+ case [2]byte{0xFF, 0xFE}:
+ return decodeUtf16(b[2:], binary.LittleEndian), true
+ case [2]byte{0xFE, 0xFF}:
+ return decodeUtf16(b[2:], binary.BigEndian), true
+ }
+ }
+ if len(b) >= 3 && b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF {
+ b = b[3:]
+ }
+ return string(b), true
+}
+
+func decodeUtf16(b []byte, order binary.ByteOrder) string {
+ ints := make([]uint16, len(b)/2)
+ if err := binary.Read(bytes.NewReader(b), order, &ints); err != nil {
+ return ""
+ }
+ return string(utf16.Decode(ints))
+}
+
+func (h *compilerHost) ReadDirectory(rootDir string, extensions []string) []FileInfo {
+ var fileInfos []FileInfo
+ filepath.Walk(rootDir, func(path string, info fs.FileInfo, err error) error {
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ if !info.IsDir() && slices.ContainsFunc(extensions, func(ext string) bool { return strings.HasSuffix(path, ext) }) {
+ fileInfos = append(fileInfos, FileInfo{Name: path, Size: info.Size()})
+ }
+ return nil
+ })
+ return fileInfos
+}
+
+func (h *compilerHost) AbsFileName(fileName string) string {
+ absFileName, err := filepath.Abs(fileName)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ return absFileName
+}
+
+func (h *compilerHost) RunTask(task func()) {
+ if h.singleThreaded {
+ task()
+ return
+ }
+ h.wg.Add(1)
+ go func() {
+ defer h.wg.Done()
+ task()
+ }()
+}
+
+func (h *compilerHost) WaitForTasks() {
+ if h.singleThreaded {
+ return
+ }
+ h.wg.Wait()
+}
diff --git a/internal/compiler/parser.go b/internal/compiler/parser.go
new file mode 100644
index 0000000000..885e5ae7a3
--- /dev/null
+++ b/internal/compiler/parser.go
@@ -0,0 +1,5916 @@
+package compiler
+
+import (
+ "path"
+ "strings"
+
+ "github.com/microsoft/typescript-go/internal/compiler/diagnostics"
+)
+
+type ParsingContext int
+
+const (
+ PCSourceElements ParsingContext = iota // Elements in source file
+ PCBlockStatements // Statements in block
+ PCSwitchClauses // Clauses in switch statement
+ PCSwitchClauseStatements // Statements in switch clause
+ PCTypeMembers // Members in interface or type literal
+ PCClassMembers // Members in class declaration
+ PCEnumMembers // Members in enum declaration
+ PCHeritageClauseElement // Elements in a heritage clause
+ PCVariableDeclarations // Variable declarations in variable statement
+ PCObjectBindingElements // Binding elements in object binding list
+ PCArrayBindingElements // Binding elements in array binding list
+ PCArgumentExpressions // Expressions in argument list
+ PCObjectLiteralMembers // Members in object literal
+ PCJsxAttributes // Attributes in jsx element
+ PCJsxChildren // Things between opening and closing JSX tags
+ PCArrayLiteralMembers // Members in array literal
+ PCParameters // Parameters in parameter list
+ PCJSDocParameters // JSDoc parameters in parameter list of JSDoc function type
+ PCRestProperties // Property names in a rest type list
+ PCTypeParameters // Type parameters in type parameter list
+ PCTypeArguments // Type arguments in type argument list
+ PCTupleElementTypes // Element types in tuple element type list
+ PCHeritageClauses // Heritage clauses for a class or interface declaration.
+ PCImportOrExportSpecifiers // Named import clause's import specifier list
+ PCImportAttributes // Import attributes
+ PCJSDocComment // Parsing via JSDocParser
+ PCCount // Number of parsing contexts
+)
+
+type ParsingContexts int
+
+type Parser struct {
+ scanner *Scanner
+ factory NodeFactory
+ fileName string
+ sourceText string
+ languageVersion ScriptTarget
+ scriptKind ScriptKind
+ languageVariant LanguageVariant
+ contextFlags NodeFlags
+ token SyntaxKind
+ parsingContexts ParsingContexts
+ diagnostics []*Diagnostic
+ identifiers map[string]bool
+ sourceFlags NodeFlags
+ notParenthesizedArrow map[int]bool
+ identifierPool Pool[Identifier]
+}
+
+func NewParser() *Parser {
+ p := &Parser{}
+ p.scanner = NewScanner()
+ return p
+}
+
+func ParseSourceFile(fileName string, sourceText string, languageVersion ScriptTarget) *SourceFile {
+ var p Parser
+ p.scanner = NewScanner()
+ p.fileName = path.Clean(fileName)
+ p.sourceText = sourceText
+ p.languageVersion = languageVersion
+ p.scriptKind = ensureScriptKind(fileName, ScriptKindUnknown)
+ p.languageVariant = getLanguageVariant(p.scriptKind)
+ p.identifiers = make(map[string]bool)
+ switch p.scriptKind {
+ case ScriptKindJS, ScriptKindJSX:
+ p.contextFlags = NodeFlagsJavaScriptFile
+ case ScriptKindJSON:
+ p.contextFlags = NodeFlagsJavaScriptFile | NodeFlagsJsonFile
+ default:
+ p.contextFlags = NodeFlagsNone
+ }
+ p.scanner.SetText(p.sourceText)
+ p.scanner.SetOnError(p.scanError)
+ p.scanner.SetScriptTarget(p.languageVersion)
+ p.scanner.SetLanguageVariant(p.languageVariant)
+ p.nextToken()
+ return p.parseSourceFileWorker()
+}
+
+func (p *Parser) scanError(message *diagnostics.Message, pos int, len int, args ...any) {
+ p.parseErrorAtRange(NewTextRange(pos, pos+len), message, args...)
+}
+
+func (p *Parser) parseErrorAt(pos int, end int, message *diagnostics.Message, args ...any) *Diagnostic {
+ return p.parseErrorAtRange(NewTextRange(pos, end), message, args...)
+}
+
+func (p *Parser) parseErrorAtCurrentToken(message *diagnostics.Message, args ...any) *Diagnostic {
+ return p.parseErrorAtRange(p.scanner.TokenRange(), message, args...)
+}
+
+func (p *Parser) parseErrorAtRange(loc TextRange, message *diagnostics.Message, args ...any) *Diagnostic {
+ // Don't report another error if it would just be at the same location as the last error
+ if len(p.diagnostics) == 0 || p.diagnostics[len(p.diagnostics)-1].Loc() != loc {
+ result := NewDiagnostic(nil, loc, message, args...)
+ p.diagnostics = append(p.diagnostics, result)
+ return result
+ }
+ return nil
+}
+
+type ParserState struct {
+ scannerState ScannerState
+ contextFlags NodeFlags
+ diagnosticsLen int
+}
+
+func (p *Parser) mark() ParserState {
+ return ParserState{scannerState: p.scanner.Mark(), contextFlags: p.contextFlags, diagnosticsLen: len(p.diagnostics)}
+}
+
+func (p *Parser) rewind(state ParserState) {
+ p.scanner.Rewind(state.scannerState)
+ p.token = p.scanner.token
+ p.contextFlags = state.contextFlags
+ p.diagnostics = p.diagnostics[0:state.diagnosticsLen]
+}
+
+func (p *Parser) lookAhead(callback func() bool) bool {
+ state := p.mark()
+ result := callback()
+ p.rewind(state)
+ return result
+}
+
+func (p *Parser) nextToken() SyntaxKind {
+ p.token = p.scanner.Scan()
+ return p.token
+}
+
+func (p *Parser) nodePos() int {
+ return p.scanner.TokenFullStart()
+}
+
+func (p *Parser) hasPrecedingLineBreak() bool {
+ return p.scanner.HasPrecedingLineBreak()
+}
+
+func (p *Parser) hasPrecedingJSDocComment() bool {
+ return false // !!!
+}
+
+func (p *Parser) parseSourceFileWorker() *SourceFile {
+ isDeclarationFile := isDeclarationFileName(p.fileName)
+ if isDeclarationFile {
+ p.contextFlags |= NodeFlagsAmbient
+ }
+ pos := p.nodePos()
+ statements := parseList(p, PCSourceElements, p.parseStatement)
+ node := p.factory.NewSourceFile(p.sourceText, p.fileName, statements)
+ p.finishNode(node, pos)
+ result := node.AsSourceFile()
+ result.diagnostics = attachFileToDiagnostics(p.diagnostics, result)
+ result.externalModuleIndicator = isFileProbablyExternalModule(result)
+ result.isDeclarationFile = isDeclarationFile
+ return result
+}
+
+func parseList(p *Parser, kind ParsingContext, parseElement func() *Node) []*Node {
+ saveParsingContexts := p.parsingContexts
+ p.parsingContexts |= 1 << kind
+ list := []*Node{}
+ for !p.isListTerminator(kind) {
+ if p.isListElement(kind, false /*inErrorRecovery*/) {
+ list = append(list, parseElement())
+ continue
+ }
+ if p.abortParsingListOrMoveToNextToken(kind) {
+ break
+ }
+ }
+ p.parsingContexts = saveParsingContexts
+ return list
+}
+
+// Return a non-nil (but possibly empty) slice if parsing was successful, or nil if parseElement returned nil
+func parseDelimitedList(p *Parser, kind ParsingContext, parseElement func() *Node) []*Node {
+ saveParsingContexts := p.parsingContexts
+ p.parsingContexts |= 1 << kind
+ list := []*Node{}
+ for {
+ if p.isListElement(kind, false /*inErrorRecovery*/) {
+ startPos := p.nodePos()
+ element := parseElement()
+ if element == nil {
+ p.parsingContexts = saveParsingContexts
+ // Return nil list to indicate parseElement failed
+ return nil
+ }
+ list = append(list, element)
+ if p.parseOptional(SyntaxKindCommaToken) {
+ // No need to check for a zero length node since we know we parsed a comma
+ continue
+ }
+ if p.isListTerminator(kind) {
+ break
+ }
+ // We didn't get a comma, and the list wasn't terminated, explicitly parse
+ // out a comma so we give a good error message.
+ if p.token != SyntaxKindCommaToken && kind == PCEnumMembers {
+ p.parseErrorAtCurrentToken(diagnostics.An_enum_member_name_must_be_followed_by_a_or)
+ } else {
+ p.parseExpected(SyntaxKindCommaToken)
+ }
+ // If the token was a semicolon, and the caller allows that, then skip it and
+ // continue. This ensures we get back on track and don't result in tons of
+ // parse errors. For example, this can happen when people do things like use
+ // a semicolon to delimit object literal members. Note: we'll have already
+ // reported an error when we called parseExpected above.
+ if (kind == PCObjectLiteralMembers || kind == PCImportAttributes) && p.token == SyntaxKindSemicolonToken && !p.hasPrecedingLineBreak() {
+ p.nextToken()
+ }
+ if startPos == p.nodePos() {
+ // What we're parsing isn't actually remotely recognizable as a element and we've consumed no tokens whatsoever
+ // Consume a token to advance the parser in some way and avoid an infinite loop
+ // This can happen when we're speculatively parsing parenthesized expressions which we think may be arrow functions,
+ // or when a modifier keyword which is disallowed as a parameter name (ie, `static` in strict mode) is supplied
+ p.nextToken()
+ }
+ continue
+ }
+ if p.isListTerminator(kind) {
+ break
+ }
+ if p.abortParsingListOrMoveToNextToken(kind) {
+ break
+ }
+ }
+ p.parsingContexts = saveParsingContexts
+ return list
+}
+
+// Return a non-nil (but possibly empty) slice if parsing was successful, or nil if opening token wasn't found
+// or parseElement returned nil
+func parseBracketedList(p *Parser, kind ParsingContext, parseElement func() *Node, open SyntaxKind, close SyntaxKind) []*Node {
+ if p.parseExpected(open) {
+ result := parseDelimitedList(p, kind, parseElement)
+ p.parseExpected(close)
+ return result
+ }
+ return nil
+}
+
+// Returns true if we should abort parsing.
+func (p *Parser) abortParsingListOrMoveToNextToken(kind ParsingContext) bool {
+ p.parsingContextErrors(kind)
+ if p.isInSomeParsingContext() {
+ return true
+ }
+ p.nextToken()
+ return false
+}
+
+// True if positioned at element or terminator of the current list or any enclosing list
+func (p *Parser) isInSomeParsingContext() bool {
+ // We should be in at least one parsing context, be it SourceElements while parsing
+ // a SourceFile, or JSDocComment when lazily parsing JSDoc.
+ // Debug.assert(parsingContext, "Missing parsing context")
+ for kind := ParsingContext(0); kind < PCCount; kind++ {
+ if p.parsingContexts&(1<' then we just stop immediately. We've got an
+ // arrow function here and it's going to be very unlikely that we'll resynchronize and get
+ // another variable declaration.
+ return p.canParseSemicolon() || p.token == SyntaxKindInKeyword || p.token == SyntaxKindOfKeyword || p.token == SyntaxKindEqualsGreaterThanToken
+ case PCTypeParameters:
+ // Tokens other than '>' are here for better error recovery
+ return p.token == SyntaxKindGreaterThanToken || p.token == SyntaxKindOpenParenToken || p.token == SyntaxKindOpenBraceToken || p.token == SyntaxKindExtendsKeyword || p.token == SyntaxKindImplementsKeyword
+ case PCArgumentExpressions:
+ // Tokens other than ')' are here for better error recovery
+ return p.token == SyntaxKindCloseParenToken || p.token == SyntaxKindSemicolonToken
+ case PCArrayLiteralMembers, PCTupleElementTypes, PCArrayBindingElements:
+ return p.token == SyntaxKindCloseBracketToken
+ case PCJSDocParameters, PCParameters, PCRestProperties:
+ // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
+ return p.token == SyntaxKindCloseParenToken || p.token == SyntaxKindCloseBracketToken /*|| token == SyntaxKindOpenBraceToken*/
+ case PCTypeArguments:
+ // All other tokens should cause the type-argument to terminate except comma token
+ return p.token != SyntaxKindCommaToken
+ case PCHeritageClauses:
+ return p.token == SyntaxKindOpenBraceToken || p.token == SyntaxKindCloseBraceToken
+ case PCJsxAttributes:
+ return p.token == SyntaxKindGreaterThanToken || p.token == SyntaxKindSlashToken
+ case PCJsxChildren:
+ return p.token == SyntaxKindLessThanToken && p.lookAhead(p.nextTokenIsSlash)
+ }
+ return false
+}
+
+func (p *Parser) parseExpectedMatchingBrackets(openKind SyntaxKind, closeKind SyntaxKind, openParsed bool, openPosition int) {
+ if p.token == closeKind {
+ p.nextToken()
+ return
+ }
+ lastError := p.parseErrorAtCurrentToken(diagnostics.X_0_expected, TokenToString(closeKind))
+ if !openParsed {
+ return
+ }
+ if lastError != nil {
+ related := NewDiagnostic(nil, NewTextRange(openPosition, openPosition+1), diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, TokenToString(openKind), TokenToString(closeKind))
+ addRelatedInfo(lastError, related)
+ }
+}
+
+func (p *Parser) parseOptional(token SyntaxKind) bool {
+ if p.token == token {
+ p.nextToken()
+ return true
+ }
+ return false
+}
+
+func (p *Parser) parseExpected(kind SyntaxKind) bool {
+ return p.parseExpectedWithDiagnostic(kind, nil, true)
+}
+
+func (p *Parser) parseExpectedWithoutAdvancing(kind SyntaxKind) bool {
+ return p.parseExpectedWithDiagnostic(kind, nil, false)
+}
+
+func (p *Parser) parseExpectedWithDiagnostic(kind SyntaxKind, message *diagnostics.Message, shouldAdvance bool) bool {
+ if p.token == kind {
+ if shouldAdvance {
+ p.nextToken()
+ }
+ return true
+ }
+ // Report specific message if provided with one. Otherwise, report generic fallback message.
+ if message != nil {
+ p.parseErrorAtCurrentToken(message)
+ } else {
+ p.parseErrorAtCurrentToken(diagnostics.X_0_expected, TokenToString(kind))
+ }
+ return false
+}
+
+func (p *Parser) parseStatement() *Statement {
+ switch p.token {
+ case SyntaxKindSemicolonToken:
+ return p.parseEmptyStatement()
+ case SyntaxKindOpenBraceToken:
+ return p.parseBlock(false /*ignoreMissingOpenBrace*/, nil)
+ case SyntaxKindVarKeyword:
+ return p.parseVariableStatement(p.nodePos(), p.hasPrecedingJSDocComment(), nil /*modifiers*/)
+ case SyntaxKindLetKeyword:
+ if p.isLetDeclaration() {
+ return p.parseVariableStatement(p.nodePos(), p.hasPrecedingJSDocComment(), nil /*modifiers*/)
+ }
+ case SyntaxKindAwaitKeyword:
+ if p.isAwaitUsingDeclaration() {
+ return p.parseVariableStatement(p.nodePos(), p.hasPrecedingJSDocComment(), nil /*modifiers*/)
+ }
+ case SyntaxKindUsingKeyword:
+ if p.isUsingDeclaration() {
+ return p.parseVariableStatement(p.nodePos(), p.hasPrecedingJSDocComment(), nil /*modifiers*/)
+ }
+ case SyntaxKindFunctionKeyword:
+ return p.parseFunctionDeclaration(p.nodePos(), p.hasPrecedingJSDocComment(), nil /*modifiers*/)
+ case SyntaxKindClassKeyword:
+ return p.parseClassDeclaration(p.nodePos(), p.hasPrecedingJSDocComment(), nil /*modifiers*/)
+ case SyntaxKindIfKeyword:
+ return p.parseIfStatement()
+ case SyntaxKindDoKeyword:
+ return p.parseDoStatement()
+ case SyntaxKindWhileKeyword:
+ return p.parseWhileStatement()
+ case SyntaxKindForKeyword:
+ return p.parseForOrForInOrForOfStatement()
+ case SyntaxKindContinueKeyword:
+ return p.parseContinueStatement()
+ case SyntaxKindBreakKeyword:
+ return p.parseBreakStatement()
+ case SyntaxKindReturnKeyword:
+ return p.parseReturnStatement()
+ case SyntaxKindWithKeyword:
+ return p.parseWithStatement()
+ case SyntaxKindSwitchKeyword:
+ return p.parseSwitchStatement()
+ case SyntaxKindThrowKeyword:
+ return p.parseThrowStatement()
+ case SyntaxKindTryKeyword, SyntaxKindCatchKeyword, SyntaxKindFinallyKeyword:
+ return p.parseTryStatement()
+ case SyntaxKindDebuggerKeyword:
+ return p.parseDebuggerStatement()
+ case SyntaxKindAtToken:
+ return p.parseDeclaration()
+ case SyntaxKindAsyncKeyword, SyntaxKindInterfaceKeyword, SyntaxKindTypeKeyword, SyntaxKindModuleKeyword, SyntaxKindNamespaceKeyword,
+ SyntaxKindDeclareKeyword, SyntaxKindConstKeyword, SyntaxKindEnumKeyword, SyntaxKindExportKeyword, SyntaxKindImportKeyword,
+ SyntaxKindPrivateKeyword, SyntaxKindProtectedKeyword, SyntaxKindPublicKeyword, SyntaxKindAbstractKeyword, SyntaxKindAccessorKeyword,
+ SyntaxKindStaticKeyword, SyntaxKindReadonlyKeyword, SyntaxKindGlobalKeyword:
+ if p.isStartOfDeclaration() {
+ return p.parseDeclaration()
+ }
+ }
+ return p.parseExpressionOrLabeledStatement()
+}
+
+func (p *Parser) parseDeclaration() *Statement {
+ // `parseListElement` attempted to get the reused node at this position,
+ // but the ambient context flag was not yet set, so the node appeared
+ // not reusable in that context.
+ pos := p.nodePos()
+ hasJSDoc := p.hasPrecedingJSDocComment()
+ modifierList := p.parseModifiersWithOptions( /*allowDecorators*/ true, false /*permitConstAsModifier*/, false /*stopOnStartOfClassStaticBlock*/)
+ isAmbient := modifierList != nil && some(modifierList.AsModifierList().modifiers, isDeclareModifier)
+ if isAmbient {
+ // !!! incremental parsing
+ // node := p.tryReuseAmbientDeclaration(pos)
+ // if node {
+ // return node
+ // }
+ for _, m := range modifierList.AsModifierList().modifiers {
+ m.flags |= NodeFlagsAmbient
+ }
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsAmbient, true)
+ result := p.parseDeclarationWorker(pos, hasJSDoc, modifierList)
+ p.contextFlags = saveContextFlags
+ return result
+ } else {
+ return p.parseDeclarationWorker(pos, hasJSDoc, modifierList)
+ }
+}
+
+func (p *Parser) parseDeclarationWorker(pos int, hasJSDoc bool, modifierList *Node) *Statement {
+ switch p.token {
+ case SyntaxKindVarKeyword, SyntaxKindLetKeyword, SyntaxKindConstKeyword, SyntaxKindUsingKeyword, SyntaxKindAwaitKeyword:
+ return p.parseVariableStatement(pos, hasJSDoc, modifierList)
+ case SyntaxKindFunctionKeyword:
+ return p.parseFunctionDeclaration(pos, hasJSDoc, modifierList)
+ case SyntaxKindClassKeyword:
+ return p.parseClassDeclaration(pos, hasJSDoc, modifierList)
+ case SyntaxKindInterfaceKeyword:
+ return p.parseInterfaceDeclaration(pos, hasJSDoc, modifierList)
+ case SyntaxKindTypeKeyword:
+ return p.parseTypeAliasDeclaration(pos, hasJSDoc, modifierList)
+ case SyntaxKindEnumKeyword:
+ return p.parseEnumDeclaration(pos, hasJSDoc, modifierList)
+ case SyntaxKindGlobalKeyword, SyntaxKindModuleKeyword, SyntaxKindNamespaceKeyword:
+ return p.parseModuleDeclaration(pos, hasJSDoc, modifierList)
+ case SyntaxKindImportKeyword:
+ return p.parseImportDeclarationOrImportEqualsDeclaration(pos, hasJSDoc, modifierList)
+ case SyntaxKindExportKeyword:
+ p.nextToken()
+ switch p.token {
+ case SyntaxKindDefaultKeyword, SyntaxKindEqualsToken:
+ return p.parseExportAssignment(pos, hasJSDoc, modifierList)
+ case SyntaxKindAsKeyword:
+ return p.parseNamespaceExportDeclaration(pos, hasJSDoc, modifierList)
+ default:
+ return p.parseExportDeclaration(pos, hasJSDoc, modifierList)
+ }
+ }
+ if modifierList != nil {
+ // We reached this point because we encountered decorators and/or modifiers and assumed a declaration
+ // would follow. For recovery and error reporting purposes, return an incomplete declaration.
+ p.parseErrorAt(p.nodePos(), p.nodePos(), diagnostics.Declaration_expected)
+ result := p.factory.NewMissingDeclaration(modifierList)
+ p.finishNode(result, pos)
+ return result
+ }
+ panic("Unhandled case in parseDeclarationWorker")
+}
+
+func isDeclareModifier(modifier *Node) bool {
+ return modifier.kind == SyntaxKindDeclareKeyword
+}
+
+func (p *Parser) isLetDeclaration() bool {
+ // In ES6 'let' always starts a lexical declaration if followed by an identifier or {
+ // or [.
+ return p.lookAhead(p.nextTokenIsBindingIdentifierOrStartOfDestructuring)
+}
+
+func (p *Parser) nextTokenIsBindingIdentifierOrStartOfDestructuring() bool {
+ p.nextToken()
+ return p.isBindingIdentifier() || p.token == SyntaxKindOpenBraceToken || p.token == SyntaxKindOpenBracketToken
+}
+
+func (p *Parser) parseBlock(ignoreMissingOpenBrace bool, diagnosticMessage *diagnostics.Message) *Node {
+ pos := p.nodePos()
+ // !!! JSDOC
+ openBracePosition := p.scanner.TokenStart()
+ openBraceParsed := p.parseExpectedWithDiagnostic(SyntaxKindOpenBraceToken, diagnosticMessage, true /*shouldAdvance*/)
+ multiline := false
+ var statements []*Statement
+ if openBraceParsed || ignoreMissingOpenBrace {
+ multiline = p.hasPrecedingLineBreak()
+ statements = parseList(p, PCBlockStatements, p.parseStatement)
+ p.parseExpectedMatchingBrackets(SyntaxKindOpenBraceToken, SyntaxKindCloseBraceToken, openBraceParsed, openBracePosition)
+ if p.token == SyntaxKindEqualsToken {
+ p.parseErrorAtCurrentToken(diagnostics.Declaration_or_statement_expected_This_follows_a_block_of_statements_so_if_you_intended_to_write_a_destructuring_assignment_you_might_need_to_wrap_the_whole_assignment_in_parentheses)
+ p.nextToken()
+ }
+ }
+ result := p.factory.NewBlock(statements, multiline)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseEmptyStatement() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindSemicolonToken)
+ result := p.factory.NewEmptyStatement()
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseIfStatement() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindIfKeyword)
+ openParenPosition := p.scanner.TokenStart()
+ openParenParsed := p.parseExpected(SyntaxKindOpenParenToken)
+ expression := p.parseExpressionAllowIn()
+ p.parseExpectedMatchingBrackets(SyntaxKindOpenParenToken, SyntaxKindCloseParenToken, openParenParsed, openParenPosition)
+ thenStatement := p.parseStatement()
+ var elseStatement *Statement
+ if p.parseOptional(SyntaxKindElseKeyword) {
+ elseStatement = p.parseStatement()
+ }
+ result := p.factory.NewIfStatement(expression, thenStatement, elseStatement)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseDoStatement() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindDoKeyword)
+ statement := p.parseStatement()
+ p.parseExpected(SyntaxKindWhileKeyword)
+ openParenPosition := p.scanner.TokenStart()
+ openParenParsed := p.parseExpected(SyntaxKindOpenParenToken)
+ expression := p.parseExpressionAllowIn()
+ p.parseExpectedMatchingBrackets(SyntaxKindOpenParenToken, SyntaxKindCloseParenToken, openParenParsed, openParenPosition)
+ // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html
+ // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in
+ // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby
+ // do;while(0)x will have a semicolon inserted before x.
+ p.parseOptional(SyntaxKindSemicolonToken)
+ result := p.factory.NewDoStatement(statement, expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseWhileStatement() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindWhileKeyword)
+ openParenPosition := p.scanner.TokenStart()
+ openParenParsed := p.parseExpected(SyntaxKindOpenParenToken)
+ expression := p.parseExpressionAllowIn()
+ p.parseExpectedMatchingBrackets(SyntaxKindOpenParenToken, SyntaxKindCloseParenToken, openParenParsed, openParenPosition)
+ statement := p.parseStatement()
+ result := p.factory.NewWhileStatement(expression, statement)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseForOrForInOrForOfStatement() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindForKeyword)
+ awaitToken := p.parseOptionalToken(SyntaxKindAwaitKeyword)
+ p.parseExpected(SyntaxKindOpenParenToken)
+ var initializer *ForInitializer
+ if p.token != SyntaxKindSemicolonToken {
+ if p.token == SyntaxKindVarKeyword || p.token == SyntaxKindLetKeyword || p.token == SyntaxKindConstKeyword ||
+ p.token == SyntaxKindUsingKeyword && p.lookAhead(p.nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLineDisallowOf) ||
+ // this one is meant to allow of
+ p.token == SyntaxKindAwaitKeyword && p.lookAhead(p.nextIsUsingKeywordThenBindingIdentifierOrStartOfObjectDestructuringOnSameLine) {
+ initializer = p.parseVariableDeclarationList(true /*inForStatementInitializer*/)
+ } else {
+ initializer = doInContext(p, NodeFlagsDisallowInContext, true, p.parseExpression)
+ }
+ }
+ var result *Statement
+ switch {
+ case awaitToken != nil && p.parseExpected(SyntaxKindOfKeyword) || awaitToken == nil && p.parseOptional(SyntaxKindOfKeyword):
+ expression := doInContext(p, NodeFlagsDisallowInContext, false, p.parseAssignmentExpressionOrHigher)
+ p.parseExpected(SyntaxKindCloseParenToken)
+ result = p.factory.NewForInOrOfStatement(SyntaxKindForOfStatement, awaitToken, initializer, expression, p.parseStatement())
+ case p.parseOptional(SyntaxKindInKeyword):
+ expression := p.parseExpressionAllowIn()
+ p.parseExpected(SyntaxKindCloseParenToken)
+ result = p.factory.NewForInOrOfStatement(SyntaxKindForInStatement, nil /*awaitToken*/, initializer, expression, p.parseStatement())
+ default:
+ p.parseExpected(SyntaxKindSemicolonToken)
+ var condition *Expression
+ if p.token != SyntaxKindSemicolonToken && p.token != SyntaxKindCloseParenToken {
+ condition = p.parseExpressionAllowIn()
+ }
+ p.parseExpected(SyntaxKindSemicolonToken)
+ var incrementor *Expression
+ if p.token != SyntaxKindCloseParenToken {
+ incrementor = p.parseExpressionAllowIn()
+ }
+ p.parseExpected(SyntaxKindCloseParenToken)
+ result = p.factory.NewForStatement(initializer, condition, incrementor, p.parseStatement())
+ }
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseBreakStatement() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindBreakKeyword)
+ label := p.parseIdentifierUnlessAtSemicolon()
+ p.parseSemicolon()
+ result := p.factory.NewBreakStatement(label)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseContinueStatement() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindContinueKeyword)
+ label := p.parseIdentifierUnlessAtSemicolon()
+ p.parseSemicolon()
+ result := p.factory.NewContinueStatement(label)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseIdentifierUnlessAtSemicolon() *Node {
+ if !p.canParseSemicolon() {
+ return p.parseIdentifier()
+ }
+ return nil
+}
+
+func (p *Parser) parseReturnStatement() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindReturnKeyword)
+ var expression *Expression
+ if !p.canParseSemicolon() {
+ expression = p.parseExpressionAllowIn()
+ }
+ p.parseSemicolon()
+ result := p.factory.NewReturnStatement(expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseWithStatement() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindWithKeyword)
+ openParenPosition := p.scanner.TokenStart()
+ openParenParsed := p.parseExpected(SyntaxKindOpenParenToken)
+ expression := p.parseExpressionAllowIn()
+ p.parseExpectedMatchingBrackets(SyntaxKindOpenParenToken, SyntaxKindCloseParenToken, openParenParsed, openParenPosition)
+ statement := doInContext(p, NodeFlagsInWithStatement, true, p.parseStatement)
+ result := p.factory.NewWithStatement(expression, statement)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseCaseClause() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindCaseKeyword)
+ expression := p.parseExpressionAllowIn()
+ p.parseExpected(SyntaxKindColonToken)
+ statements := parseList(p, PCSwitchClauseStatements, p.parseStatement)
+ result := p.factory.NewCaseOrDefaultClause(SyntaxKindCaseClause, expression, statements)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseDefaultClause() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindDefaultKeyword)
+ p.parseExpected(SyntaxKindColonToken)
+ statements := parseList(p, PCSwitchClauseStatements, p.parseStatement)
+ result := p.factory.NewCaseOrDefaultClause(SyntaxKindDefaultClause, nil /*expression*/, statements)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseCaseOrDefaultClause() *Node {
+ if p.token == SyntaxKindCaseKeyword {
+ return p.parseCaseClause()
+ }
+ return p.parseDefaultClause()
+}
+
+func (p *Parser) parseCaseBlock() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindOpenBraceToken)
+ clauses := parseList(p, PCSwitchClauses, p.parseCaseOrDefaultClause)
+ p.parseExpected(SyntaxKindCloseBraceToken)
+ result := p.factory.NewCaseBlock(clauses)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseSwitchStatement() *Node {
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindSwitchKeyword)
+ p.parseExpected(SyntaxKindOpenParenToken)
+ expression := p.parseExpressionAllowIn()
+ p.parseExpected(SyntaxKindCloseParenToken)
+ caseBlock := p.parseCaseBlock()
+ result := p.factory.NewSwitchStatement(expression, caseBlock)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseThrowStatement() *Node {
+ // ThrowStatement[Yield] :
+ // throw [no LineTerminator here]Expression[In, ?Yield];
+ pos := p.nodePos()
+ //const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindThrowKeyword)
+ // Because of automatic semicolon insertion, we need to report error if this
+ // throw could be terminated with a semicolon. Note: we can't call 'parseExpression'
+ // directly as that might consume an expression on the following line.
+ // Instead, we create a "missing" identifier, but don't report an error. The actual error
+ // will be reported in the grammar walker.
+ var expression *Expression
+ if !p.hasPrecedingLineBreak() {
+ expression = p.parseExpressionAllowIn()
+ } else {
+ expression = p.createMissingIdentifier()
+ }
+ if !p.tryParseSemicolon() {
+ p.parseErrorForMissingSemicolonAfter(expression)
+ }
+ result := p.factory.NewThrowStatement(expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+// TODO: Review for error recovery
+func (p *Parser) parseTryStatement() *Node {
+ pos := p.nodePos()
+ // const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindTryKeyword)
+ tryBlock := p.parseBlock(false /*ignoreMissingOpenBrace*/, nil)
+ var catchClause *Node
+ if p.token == SyntaxKindCatchKeyword {
+ catchClause = p.parseCatchClause()
+ }
+ // If we don't have a catch clause, then we must have a finally clause. Try to parse
+ // one out no matter what.
+ var finallyBlock *Node
+ if catchClause == nil || p.token == SyntaxKindFinallyKeyword {
+ p.parseExpectedWithDiagnostic(SyntaxKindFinallyKeyword, diagnostics.X_catch_or_finally_expected, true /*shouldAdvance*/)
+ finallyBlock = p.parseBlock(false /*ignoreMissingOpenBrace*/, nil)
+ }
+ result := p.factory.NewTryStatement(tryBlock, catchClause, finallyBlock)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseCatchClause() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindCatchKeyword)
+ var variableDeclaration *Node
+ if p.parseOptional(SyntaxKindOpenParenToken) {
+ variableDeclaration = p.parseVariableDeclaration()
+ p.parseExpected(SyntaxKindCloseParenToken)
+ }
+ block := p.parseBlock(false /*ignoreMissingOpenBrace*/, nil)
+ result := p.factory.NewCatchClause(variableDeclaration, block)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseDebuggerStatement() *Node {
+ pos := p.nodePos()
+ // const hasJSDoc = hasPrecedingJSDocComment();
+ p.parseExpected(SyntaxKindDebuggerKeyword)
+ p.parseSemicolon()
+ result := p.factory.NewDebuggerStatement()
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseExpressionOrLabeledStatement() *Statement {
+ // Avoiding having to do the lookahead for a labeled statement by just trying to parse
+ // out an expression, seeing if it is identifier and then seeing if it is followed by
+ // a colon.
+ pos := p.nodePos()
+ // !!! JSDoc
+ expression := p.parseExpression()
+ if expression.kind == SyntaxKindIdentifier && p.parseOptional(SyntaxKindColonToken) {
+ result := p.factory.NewLabeledStatement(expression, p.parseStatement())
+ p.finishNode(result, pos)
+ return result
+ }
+ // if !p.tryParseSemicolon() {
+ // p.parseErrorForMissingSemicolonAfter(expression)
+ // }
+ p.parseSemicolon()
+ result := p.factory.NewExpressionStatement(expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseVariableStatement(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ declarationList := p.parseVariableDeclarationList(false /*inForStatementInitializer*/)
+ p.parseSemicolon()
+ result := p.factory.NewVariableStatement(modifiers, declarationList)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseVariableDeclarationList(inForStatementInitializer bool) *Node {
+ pos := p.nodePos()
+ var flags NodeFlags
+ switch p.token {
+ case SyntaxKindVarKeyword:
+ flags = NodeFlagsNone
+ case SyntaxKindLetKeyword:
+ flags = NodeFlagsLet
+ case SyntaxKindConstKeyword:
+ flags = NodeFlagsConst
+ case SyntaxKindUsingKeyword:
+ flags = NodeFlagsUsing
+ case SyntaxKindAwaitKeyword:
+ //Debug.assert(isAwaitUsingDeclaration());
+ flags = NodeFlagsAwaitUsing
+ p.nextToken()
+ default:
+ panic("Unhandled case in parseVariableDeclarationList")
+ }
+ p.nextToken()
+ // The user may have written the following:
+ //
+ // for (let of X) { }
+ //
+ // In this case, we want to parse an empty declaration list, and then parse 'of'
+ // as a keyword. The reason this is not automatic is that 'of' is a valid identifier.
+ // So we need to look ahead to determine if 'of' should be treated as a keyword in
+ // this context.
+ // The checker will then give an error that there is an empty declaration list.
+ var declarations []*Node
+ if p.token == SyntaxKindOfKeyword && p.lookAhead(p.nextIsIdentifierAndCloseParen) {
+ declarations = []*Node{}
+ } else {
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsDisallowInContext, inForStatementInitializer)
+ declarations = parseDelimitedList(p, PCVariableDeclarations, ifElse(inForStatementInitializer, p.parseVariableDeclaration, p.parseVariableDeclarationAllowExclamation))
+ p.contextFlags = saveContextFlags
+ }
+ result := p.factory.NewVariableDeclarationList(flags, declarations)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) nextIsIdentifierAndCloseParen() bool {
+ return p.nextTokenIsIdentifier() && p.nextToken() == SyntaxKindCloseParenToken
+}
+
+func (p *Parser) nextTokenIsIdentifier() bool {
+ p.nextToken()
+ return p.isIdentifier()
+}
+
+func (p *Parser) parseVariableDeclaration() *Node {
+ return p.parseVariableDeclarationWorker(false /*allowExclamation*/)
+}
+
+func (p *Parser) parseVariableDeclarationAllowExclamation() *Node {
+ return p.parseVariableDeclarationWorker(true /*allowExclamation*/)
+}
+
+func (p *Parser) parseVariableDeclarationWorker(allowExclamation bool) *Node {
+ pos := p.nodePos()
+ // !!! jsDoc
+ name := p.parseIdentifierOrPatternWithDiagnostic(diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations)
+ var exclamationToken *Node
+ if allowExclamation && name.kind == SyntaxKindIdentifier && p.token == SyntaxKindExclamationToken && !p.hasPrecedingLineBreak() {
+ exclamationToken = p.parseTokenNode()
+ }
+ typeNode := p.parseTypeAnnotation()
+ var initializer *Expression
+ if p.token != SyntaxKindInKeyword && p.token != SyntaxKindOfKeyword {
+ initializer = p.parseInitializer()
+ }
+ result := p.factory.NewVariableDeclaration(name, exclamationToken, typeNode, initializer)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseIdentifierOrPattern() *Node {
+ return p.parseIdentifierOrPatternWithDiagnostic(nil)
+}
+
+func (p *Parser) parseIdentifierOrPatternWithDiagnostic(privateIdentifierDiagnosticMessage *diagnostics.Message) *Node {
+ if p.token == SyntaxKindOpenBracketToken {
+ return p.parseArrayBindingPattern()
+ }
+ if p.token == SyntaxKindOpenBraceToken {
+ return p.parseObjectBindingPattern()
+ }
+ return p.parseBindingIdentifierWithDiagnostic(privateIdentifierDiagnosticMessage)
+}
+
+func (p *Parser) parseArrayBindingPattern() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindOpenBracketToken)
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsDisallowInContext, false)
+ elements := parseDelimitedList(p, PCArrayBindingElements, p.parseArrayBindingElement)
+ p.contextFlags = saveContextFlags
+ p.parseExpected(SyntaxKindCloseBracketToken)
+ result := p.factory.NewBindingPattern(SyntaxKindArrayBindingPattern, elements)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseArrayBindingElement() *Node {
+ pos := p.nodePos()
+ var dotDotDotToken *Node
+ var name *Node
+ var initializer *Expression
+ if p.token != SyntaxKindCommaToken {
+ // These are all nil for a missing element
+ dotDotDotToken = p.parseOptionalToken(SyntaxKindDotDotDotToken)
+ name = p.parseIdentifierOrPattern()
+ initializer = p.parseInitializer()
+ }
+ result := p.factory.NewBindingElement(dotDotDotToken, nil /*propertyName*/, name, initializer)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseObjectBindingPattern() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindOpenBraceToken)
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsDisallowInContext, false)
+ elements := parseDelimitedList(p, PCObjectBindingElements, p.parseObjectBindingElement)
+ p.contextFlags = saveContextFlags
+ p.parseExpected(SyntaxKindCloseBraceToken)
+ result := p.factory.NewBindingPattern(SyntaxKindObjectBindingPattern, elements)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseObjectBindingElement() *Node {
+ pos := p.nodePos()
+ dotDotDotToken := p.parseOptionalToken(SyntaxKindDotDotDotToken)
+ tokenIsIdentifier := p.isBindingIdentifier()
+ propertyName := p.parsePropertyName()
+ var name *Node
+ if tokenIsIdentifier && p.token != SyntaxKindColonToken {
+ name = propertyName
+ propertyName = nil
+ } else {
+ p.parseExpected(SyntaxKindColonToken)
+ name = p.parseIdentifierOrPattern()
+ }
+ initializer := p.parseInitializer()
+ result := p.factory.NewBindingElement(dotDotDotToken, propertyName, name, initializer)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTokenNode() *Node {
+ pos := p.nodePos()
+ kind := p.token
+ p.nextToken()
+ result := p.factory.NewToken(kind)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseExpectedToken(kind SyntaxKind) *Node {
+ token := p.parseOptionalToken(kind)
+ if token == nil {
+ p.parseErrorAtCurrentToken(diagnostics.X_0_expected, TokenToString(kind))
+ token = p.factory.NewToken(kind)
+ p.finishNode(token, p.nodePos())
+ }
+ return token
+}
+
+func (p *Parser) parseOptionalToken(kind SyntaxKind) *Node {
+ if p.token == kind {
+ return p.parseTokenNode()
+ }
+ return nil
+}
+
+func (p *Parser) parseInitializer() *Expression {
+ if p.parseOptional(SyntaxKindEqualsToken) {
+ return p.parseAssignmentExpressionOrHigher()
+ }
+ return nil
+}
+
+func (p *Parser) parseTypeAnnotation() *TypeNode {
+ if p.parseOptional(SyntaxKindColonToken) {
+ return p.parseType()
+ }
+ return nil
+}
+
+func (p *Parser) parseFunctionDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ modifierFlags := modifiersToFlags(modifiers)
+ p.parseExpected(SyntaxKindFunctionKeyword)
+ asteriskToken := p.parseOptionalToken(SyntaxKindAsteriskToken)
+ // We don't parse the name here in await context, instead we will report a grammar error in the checker.
+ var name *Node
+ if modifierFlags&ModifierFlagsDefault == 0 || p.isBindingIdentifier() {
+ name = p.parseBindingIdentifier()
+ }
+ signatureFlags := ifElse(asteriskToken != nil, SignatureFlagsYield, SignatureFlagsNone) | ifElse(modifierFlags&ModifierFlagsAsync != 0, SignatureFlagsAwait, SignatureFlagsNone)
+ typeParameters := p.parseTypeParameters()
+ saveContextFlags := p.contextFlags
+ if modifierFlags&ModifierFlagsExport != 0 {
+ p.setContextFlags(NodeFlagsAwaitContext, true)
+ }
+ parameters := p.parseParameters(signatureFlags)
+ returnType := p.parseReturnType(SyntaxKindColonToken, false /*isType*/)
+ body := p.parseFunctionBlockOrSemicolon(signatureFlags, diagnostics.X_or_expected)
+ p.contextFlags = saveContextFlags
+ result := p.factory.NewFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, returnType, body)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseClassDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ return p.parseClassDeclarationOrExpression(pos, hasJSDoc, modifiers, SyntaxKindClassDeclaration)
+}
+
+func (p *Parser) parseClassExpression() *Node {
+ return p.parseClassDeclarationOrExpression(p.nodePos(), p.hasPrecedingJSDocComment(), nil /*modifiers*/, SyntaxKindClassExpression)
+}
+
+func (p *Parser) parseClassDeclarationOrExpression(pos int, hasJSDoc bool, modifiers *Node, kind SyntaxKind) *Node {
+ saveContextFlags := p.contextFlags
+ p.parseExpected(SyntaxKindClassKeyword)
+ // We don't parse the name here in await context, instead we will report a grammar error in the checker.
+ name := p.parseNameOfClassDeclarationOrExpression()
+ typeParameters := p.parseTypeParameters()
+ if modifiers != nil && some(modifiers.AsModifierList().modifiers, isExportModifier) {
+ p.setContextFlags(NodeFlagsAwaitContext, true /*value*/)
+ }
+ heritageClauses := p.parseHeritageClauses()
+ var members []*Node
+ if p.parseExpected(SyntaxKindOpenBraceToken) {
+ // ClassTail[Yield,Await] : (Modified) See 14.5
+ // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }
+ members = parseList(p, PCClassMembers, p.parseClassElement)
+ p.parseExpected(SyntaxKindCloseBraceToken)
+ }
+ p.contextFlags = saveContextFlags
+ var result *Node
+ if kind == SyntaxKindClassDeclaration {
+ result = p.factory.NewClassDeclaration(modifiers, name, typeParameters, heritageClauses, members)
+ } else {
+ result = p.factory.NewClassExpression(modifiers, name, typeParameters, heritageClauses, members)
+ }
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseNameOfClassDeclarationOrExpression() *Node {
+ // implements is a future reserved word so
+ // 'class implements' might mean either
+ // - class expression with omitted name, 'implements' starts heritage clause
+ // - class with name 'implements'
+ // 'isImplementsClause' helps to disambiguate between these two cases
+ if p.isBindingIdentifier() && !p.isImplementsClause() {
+ return p.createIdentifier(p.isBindingIdentifier())
+ }
+ return nil
+}
+
+func (p *Parser) isImplementsClause() bool {
+ return p.token == SyntaxKindImplementsKeyword && p.lookAhead(p.nextTokenIsIdentifierOrKeyword)
+}
+
+func isExportModifier(modifier *Node) bool {
+ return modifier.kind == SyntaxKindExportKeyword
+}
+
+func isAsyncModifier(modifier *Node) bool {
+ return modifier.kind == SyntaxKindAsyncKeyword
+}
+
+func (p *Parser) parseHeritageClauses() []*Node {
+ // ClassTail[Yield,Await] : (Modified) See 14.5
+ // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }
+ if p.isHeritageClause() {
+ return parseList(p, PCHeritageClauses, p.parseHeritageClause)
+ }
+ return []*Node{}
+}
+
+func (p *Parser) parseHeritageClause() *Node {
+ pos := p.nodePos()
+ kind := p.token
+ p.nextToken()
+ types := parseDelimitedList(p, PCHeritageClauseElement, p.parseExpressionWithTypeArguments)
+ result := p.factory.NewHeritageClause(kind, types)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseExpressionWithTypeArguments() *Node {
+ pos := p.nodePos()
+ expression := p.parseLeftHandSideExpressionOrHigher()
+ if isExpressionWithTypeArguments(expression) {
+ return expression
+ }
+ typeArguments := p.parseTypeArguments()
+ result := p.factory.NewExpressionWithTypeArguments(expression, typeArguments)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseClassElement() *Node {
+ pos := p.nodePos()
+ hasJSDoc := p.hasPrecedingJSDocComment()
+ if p.token == SyntaxKindSemicolonToken {
+ p.nextToken()
+ result := p.factory.NewSemicolonClassElement()
+ p.finishNode(result, pos)
+ return result
+ }
+ modifierList := p.parseModifiersWithOptions(true /*allowDecorators*/, true /*permitConstAsModifier*/, true /*stopOnStartOfClassStaticBlock*/)
+ if p.token == SyntaxKindStaticKeyword && p.lookAhead(p.nextTokenIsOpenBrace) {
+ return p.parseClassStaticBlockDeclaration(pos, hasJSDoc, modifierList)
+ }
+ if p.parseContextualModifier(SyntaxKindGetKeyword) {
+ return p.parseAccessorDeclaration(pos, hasJSDoc, modifierList, SyntaxKindGetAccessor, SignatureFlagsNone)
+ }
+ if p.parseContextualModifier(SyntaxKindSetKeyword) {
+ return p.parseAccessorDeclaration(pos, hasJSDoc, modifierList, SyntaxKindSetAccessor, SignatureFlagsNone)
+ }
+ if p.token == SyntaxKindConstructorKeyword || p.token == SyntaxKindStringLiteral {
+ constructorDeclaration := p.tryParseConstructorDeclaration(pos, hasJSDoc, modifierList)
+ if constructorDeclaration != nil {
+ return constructorDeclaration
+ }
+ }
+ if p.isIndexSignature() {
+ return p.parseIndexSignatureDeclaration(pos, hasJSDoc, modifierList)
+ }
+ // It is very important that we check this *after* checking indexers because
+ // the [ token can start an index signature or a computed property name
+ if tokenIsIdentifierOrKeyword(p.token) || p.token == SyntaxKindStringLiteral || p.token == SyntaxKindNumericLiteral || p.token == SyntaxKindBigintLiteral || p.token == SyntaxKindAsteriskToken || p.token == SyntaxKindOpenBracketToken {
+ isAmbient := modifierList != nil && some(modifierList.AsModifierList().modifiers, isDeclareModifier)
+ if isAmbient {
+ for _, m := range modifierList.AsModifierList().modifiers {
+ m.flags |= NodeFlagsAmbient
+ }
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsAmbient, true)
+ result := p.parsePropertyOrMethodDeclaration(pos, hasJSDoc, modifierList)
+ p.contextFlags = saveContextFlags
+ return result
+ } else {
+ return p.parsePropertyOrMethodDeclaration(pos, hasJSDoc, modifierList)
+ }
+ }
+ if modifierList != nil {
+ // treat this as a property declaration with a missing name.
+ p.parseErrorAt(p.nodePos(), p.nodePos(), diagnostics.Declaration_expected)
+ name := p.newIdentifier("")
+ return p.parsePropertyDeclaration(pos, hasJSDoc, modifierList, name, nil /*questionToken*/)
+ }
+ // 'isClassMemberStart' should have hinted not to attempt parsing.
+ panic("Should not have attempted to parse class member declaration.")
+}
+
+func (p *Parser) parseClassStaticBlockDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ p.parseExpectedToken(SyntaxKindStaticKeyword)
+ body := p.parseClassStaticBlockBody()
+ result := p.factory.NewClassStaticBlockDeclaration(modifiers, body)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseClassStaticBlockBody() *Node {
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsYieldContext, false)
+ p.setContextFlags(NodeFlagsAwaitContext, true)
+ body := p.parseBlock(false /*ignoreMissingOpenBrace*/, nil /*diagnosticMessage*/)
+ p.contextFlags = saveContextFlags
+ return body
+}
+
+func (p *Parser) tryParseConstructorDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ state := p.mark()
+ if p.token == SyntaxKindConstructorKeyword || p.token == SyntaxKindStringLiteral && p.scanner.tokenValue == "constructor" && p.lookAhead(p.nextTokenIsOpenParen) {
+ p.nextToken()
+ typeParameters := p.parseTypeParameters()
+ parameters := p.parseParameters(SignatureFlagsNone)
+ returnType := p.parseReturnType(SyntaxKindColonToken, false /*isType*/)
+ body := p.parseFunctionBlockOrSemicolon(SignatureFlagsNone, diagnostics.X_or_expected)
+ result := p.factory.NewConstructorDeclaration(modifiers, typeParameters, parameters, returnType, body)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+ }
+ p.rewind(state)
+ return nil
+}
+
+func (p *Parser) nextTokenIsOpenParen() bool {
+ return p.nextToken() == SyntaxKindOpenParenToken
+}
+
+func (p *Parser) parsePropertyOrMethodDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ asteriskToken := p.parseOptionalToken(SyntaxKindAsteriskToken)
+ name := p.parsePropertyName()
+ // Note: this is not legal as per the grammar. But we allow it in the parser and
+ // report an error in the grammar checker.
+ questionToken := p.parseOptionalToken(SyntaxKindQuestionToken)
+ if asteriskToken != nil || p.token == SyntaxKindOpenParenToken || p.token == SyntaxKindLessThanToken {
+ return p.parseMethodDeclaration(pos, hasJSDoc, modifiers, asteriskToken, name, questionToken, diagnostics.X_or_expected)
+ }
+ return p.parsePropertyDeclaration(pos, hasJSDoc, modifiers, name, questionToken)
+}
+
+func (p *Parser) parseMethodDeclaration(pos int, hasJSDoc bool, modifiers *Node, asteriskToken *Node, name *Node, questionToken *Node, diagnosticMessage *diagnostics.Message) *Node {
+ signatureFlags := ifElse(asteriskToken != nil, SignatureFlagsYield, SignatureFlagsNone) | ifElse(hasAsyncModifier(modifiers), SignatureFlagsAwait, SignatureFlagsNone)
+ typeParameters := p.parseTypeParameters()
+ parameters := p.parseParameters(signatureFlags)
+ typeNode := p.parseReturnType(SyntaxKindColonToken, false /*isType*/)
+ body := p.parseFunctionBlockOrSemicolon(signatureFlags, diagnosticMessage)
+ result := p.factory.NewMethodDeclaration(modifiers, asteriskToken, name, questionToken, typeParameters, parameters, typeNode, body)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func hasAsyncModifier(modifiers *Node) bool {
+ return modifiers != nil && some(modifiers.AsModifierList().modifiers, isAsyncModifier)
+}
+
+func (p *Parser) parsePropertyDeclaration(pos int, hasJSDoc bool, modifiers *Node, name *Node, questionToken *Node) *Node {
+ postfixToken := questionToken
+ if postfixToken == nil && !p.hasPrecedingLineBreak() {
+ postfixToken = p.parseOptionalToken(SyntaxKindExclamationToken)
+ }
+ typeNode := p.parseTypeAnnotation()
+ initializer := doInContext(p, NodeFlagsYieldContext|NodeFlagsAwaitContext|NodeFlagsDisallowInContext, false, p.parseInitializer)
+ p.parseSemicolonAfterPropertyName(name, typeNode, initializer)
+ result := p.factory.NewPropertyDeclaration(modifiers, name, postfixToken, typeNode, initializer)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseSemicolonAfterPropertyName(name *Node, typeNode *TypeNode, initializer *Expression) {
+ if p.token == SyntaxKindAtToken && !p.hasPrecedingLineBreak() {
+ p.parseErrorAtCurrentToken(diagnostics.Decorators_must_precede_the_name_and_all_keywords_of_property_declarations)
+ return
+ }
+ if p.token == SyntaxKindOpenParenToken {
+ p.parseErrorAtCurrentToken(diagnostics.Cannot_start_a_function_call_in_a_type_annotation)
+ p.nextToken()
+ return
+ }
+ if typeNode != nil && !p.canParseSemicolon() {
+ if initializer != nil {
+ p.parseErrorAtCurrentToken(diagnostics.X_0_expected, TokenToString(SyntaxKindSemicolonToken))
+ } else {
+ p.parseErrorAtCurrentToken(diagnostics.Expected_for_property_initializer)
+ }
+ return
+ }
+ if p.tryParseSemicolon() {
+ return
+ }
+ if initializer != nil {
+ p.parseErrorAtCurrentToken(diagnostics.X_0_expected, TokenToString(SyntaxKindSemicolonToken))
+ return
+ }
+ p.parseErrorForMissingSemicolonAfter(name)
+}
+
+func (p *Parser) parseErrorForMissingSemicolonAfter(node *Node) {
+ // Tagged template literals are sometimes used in places where only simple strings are allowed, i.e.:
+ // module `M1` {
+ // ^^^^^^^^^^^ This block is parsed as a template literal like module`M1`.
+ if node.kind == SyntaxKindTaggedTemplateExpression {
+ p.parseErrorAtRange(p.skipRangeTrivia(node.AsTaggedTemplateExpression().template.loc), diagnostics.Module_declaration_names_may_only_use_or_quoted_strings)
+ return
+ }
+ // Otherwise, if this isn't a well-known keyword-like identifier, give the generic fallback message.
+ var expressionText string
+ if node.kind == SyntaxKindIdentifier {
+ expressionText = node.AsIdentifier().text
+ }
+ // !!! Also call isIdentifierText(expressionText, languageVersion)
+ if expressionText == "" {
+ p.parseErrorAtCurrentToken(diagnostics.X_0_expected, TokenToString(SyntaxKindSemicolonToken))
+ return
+ }
+ pos := skipTrivia(p.sourceText, node.Pos())
+ // Some known keywords are likely signs of syntax being used improperly.
+ switch expressionText {
+ case "const", "let", "var":
+ p.parseErrorAt(pos, node.End(), diagnostics.Variable_declaration_not_allowed_at_this_location)
+ return
+ case "declare":
+ // If a declared node failed to parse, it would have emitted a diagnostic already.
+ return
+ case "interface":
+ p.parseErrorForInvalidName(diagnostics.Interface_name_cannot_be_0, diagnostics.Interface_must_be_given_a_name, SyntaxKindOpenBraceToken)
+ return
+ case "is":
+ p.parseErrorAt(pos, p.scanner.TokenStart(), diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods)
+ return
+ case "module", "namespace":
+ p.parseErrorForInvalidName(diagnostics.Namespace_name_cannot_be_0, diagnostics.Namespace_must_be_given_a_name, SyntaxKindOpenBraceToken)
+ return
+ case "type":
+ p.parseErrorForInvalidName(diagnostics.Type_alias_name_cannot_be_0, diagnostics.Type_alias_must_be_given_a_name, SyntaxKindEqualsToken)
+ return
+ }
+ // !!! The user alternatively might have misspelled or forgotten to add a space after a common keyword.
+ // const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, identity) ?? getSpaceSuggestion(expressionText);
+ // if (suggestion) {
+ // parseErrorAt(pos, node.end, Diagnostics.Unknown_keyword_or_identifier_Did_you_mean_0, suggestion);
+ // return;
+ // }
+ // Unknown tokens are handled with their own errors in the scanner
+ if p.token == SyntaxKindUnknown {
+ return
+ }
+ // Otherwise, we know this some kind of unknown word, not just a missing expected semicolon.
+ p.parseErrorAt(pos, node.End(), diagnostics.Unexpected_keyword_or_identifier)
+}
+
+func (p *Parser) parseErrorForInvalidName(nameDiagnostic *diagnostics.Message, blankDiagnostic *diagnostics.Message, tokenIfBlankName SyntaxKind) {
+ if p.token == tokenIfBlankName {
+ p.parseErrorAtCurrentToken(blankDiagnostic)
+ } else {
+ p.parseErrorAtCurrentToken(nameDiagnostic, p.scanner.TokenValue())
+ }
+}
+
+func (p *Parser) parseInterfaceDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ p.parseExpected(SyntaxKindInterfaceKeyword)
+ name := p.parseIdentifier()
+ typeParameters := p.parseTypeParameters()
+ heritageClauses := p.parseHeritageClauses()
+ members := p.parseObjectTypeMembers()
+ result := p.factory.NewInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseTypeAliasDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ p.parseExpected(SyntaxKindTypeKeyword)
+ if p.hasPrecedingLineBreak() {
+ p.parseErrorAtCurrentToken(diagnostics.Line_break_not_permitted_here)
+ }
+ name := p.parseIdentifier()
+ typeParameters := p.parseTypeParameters()
+ p.parseExpected(SyntaxKindEqualsToken)
+ var typeNode *TypeNode
+ if p.token == SyntaxKindIntrinsicKeyword && p.lookAhead(p.nextIsNotDot) {
+ typeNode = p.parseKeywordTypeNode()
+ } else {
+ typeNode = p.parseType()
+ }
+ p.parseSemicolon()
+ result := p.factory.NewTypeAliasDeclaration(modifiers, name, typeParameters, typeNode)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) nextIsNotDot() bool {
+ return p.nextToken() != SyntaxKindDotToken
+}
+
+// In an ambient declaration, the grammar only allows integer literals as initializers.
+// In a non-ambient declaration, the grammar allows uninitialized members only in a
+// ConstantEnumMemberSection, which starts at the beginning of an enum declaration
+// or any time an integer literal initializer is encountered.
+func (p *Parser) parseEnumMember() *Node {
+ pos := p.nodePos()
+ // hasJSDoc := p.hasPrecedingJSDocComment()
+ name := p.parsePropertyName()
+ initializer := doInContext(p, NodeFlagsDisallowInContext, false, p.parseInitializer)
+ result := p.factory.NewEnumMember(name, initializer)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseEnumDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ p.parseExpected(SyntaxKindEnumKeyword)
+ name := p.parseIdentifier()
+ var members []*Node
+ if p.parseExpected(SyntaxKindOpenBraceToken) {
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsYieldContext|NodeFlagsAwaitContext, false)
+ members = parseDelimitedList(p, PCEnumMembers, p.parseEnumMember)
+ p.contextFlags = saveContextFlags
+ p.parseExpected(SyntaxKindCloseBraceToken)
+ }
+ result := p.factory.NewEnumDeclaration(modifiers, name, members)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseModuleDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Statement {
+ var flags NodeFlags
+ if p.token == SyntaxKindGlobalKeyword {
+ // global augmentation
+ return p.parseAmbientExternalModuleDeclaration(pos, hasJSDoc, modifiers)
+ } else if p.parseOptional(SyntaxKindNamespaceKeyword) {
+ flags |= NodeFlagsNamespace
+ } else {
+ p.parseExpected(SyntaxKindModuleKeyword)
+ if p.token == SyntaxKindStringLiteral {
+ return p.parseAmbientExternalModuleDeclaration(pos, hasJSDoc, modifiers)
+ }
+ }
+ return p.parseModuleOrNamespaceDeclaration(pos, hasJSDoc, modifiers, flags)
+}
+
+func (p *Parser) parseAmbientExternalModuleDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ var flags NodeFlags
+ var name *Node
+ if p.token == SyntaxKindGlobalKeyword {
+ // parse 'global' as name of global scope augmentation
+ name = p.parseIdentifier()
+ flags |= NodeFlagsGlobalAugmentation
+ } else {
+ // parse string literal
+ name = p.parseLiteralExpression()
+ p.internIdentifier(getTextOfIdentifierOrLiteral(name))
+ }
+ var body *Node
+ if p.token == SyntaxKindOpenBraceToken {
+ body = p.parseModuleBlock()
+ } else {
+ p.parseSemicolon()
+ }
+ result := p.factory.NewModuleDeclaration(modifiers, name, body, flags)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseModuleBlock() *Node {
+ pos := p.nodePos()
+ var statements []*Statement
+ if p.parseExpected(SyntaxKindOpenBraceToken) {
+ statements = parseList(p, PCBlockStatements, p.parseStatement)
+ p.parseExpected(SyntaxKindCloseBraceToken)
+ }
+ result := p.factory.NewModuleBlock(statements)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseModuleOrNamespaceDeclaration(pos int, hasJSDoc bool, modifiers *Node, flags NodeFlags) *Node {
+ // If we are parsing a dotted namespace name, we want to
+ // propagate the 'Namespace' flag across the names if set.
+ namespaceFlag := flags & NodeFlagsNamespace
+ var name *Node
+ if flags&NodeFlagsNestedNamespace != 0 {
+ name = p.parseIdentifierName()
+ } else {
+ name = p.parseIdentifier()
+ }
+ var body *Node
+ if p.parseOptional(SyntaxKindDotToken) {
+ body = p.parseModuleOrNamespaceDeclaration(p.nodePos(), false /*hasJSDoc*/, nil /*modifiers*/, NodeFlagsNestedNamespace|namespaceFlag)
+ } else {
+ body = p.parseModuleBlock()
+ }
+ result := p.factory.NewModuleDeclaration(modifiers, name, body, flags)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseImportDeclarationOrImportEqualsDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Statement {
+ p.parseExpected(SyntaxKindImportKeyword)
+ afterImportPos := p.nodePos()
+ // We don't parse the identifier here in await context, instead we will report a grammar error in the checker.
+ var identifier *Node
+ if p.isIdentifier() {
+ identifier = p.parseIdentifier()
+ }
+ isTypeOnly := false
+ if identifier != nil && identifier.AsIdentifier().text == "type" &&
+ (p.token != SyntaxKindFromKeyword || p.isIdentifier() && p.lookAhead(p.nextTokenIsFromKeywordOrEqualsToken)) &&
+ (p.isIdentifier() || p.tokenAfterImportDefinitelyProducesImportDeclaration()) {
+ isTypeOnly = true
+ identifier = nil
+ if p.isIdentifier() {
+ identifier = p.parseIdentifier()
+ }
+ }
+ if identifier != nil && !p.tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration() {
+ return p.parseImportEqualsDeclaration(pos, hasJSDoc, modifiers, identifier, isTypeOnly)
+ }
+ importClause := p.tryParseImportClause(identifier, afterImportPos, isTypeOnly, false /*skipJsDocLeadingAsterisks*/)
+ moduleSpecifier := p.parseModuleSpecifier()
+ attributes := p.tryParseImportAttributes()
+ p.parseSemicolon()
+ result := p.factory.NewImportDeclaration(modifiers, importClause, moduleSpecifier, attributes)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) nextTokenIsFromKeywordOrEqualsToken() bool {
+ p.nextToken()
+ return p.token == SyntaxKindFromKeyword || p.token == SyntaxKindEqualsToken
+}
+
+func (p *Parser) tokenAfterImportDefinitelyProducesImportDeclaration() bool {
+ return p.token == SyntaxKindAsteriskToken || p.token == SyntaxKindOpenBraceToken
+}
+
+func (p *Parser) tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration() bool {
+ // In `import id ___`, the current token decides whether to produce
+ // an ImportDeclaration or ImportEqualsDeclaration.
+ return p.token == SyntaxKindCommaToken || p.token == SyntaxKindFromKeyword
+}
+
+func (p *Parser) parseImportEqualsDeclaration(pos int, hasJSDoc bool, modifiers *Node, identifier *Node, isTypeOnly bool) *Node {
+ p.parseExpected(SyntaxKindEqualsToken)
+ moduleReference := p.parseModuleReference()
+ p.parseSemicolon()
+ result := p.factory.NewImportEqualsDeclaration(modifiers, isTypeOnly, identifier, moduleReference)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseModuleReference() *Node {
+ if p.token == SyntaxKindRequireKeyword && p.lookAhead(p.nextTokenIsOpenParen) {
+ return p.parseExternalModuleReference()
+ }
+ return p.parseEntityName(false /*allowReservedWords*/, nil /*diagnosticMessage*/)
+}
+
+func (p *Parser) parseExternalModuleReference() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindRequireKeyword)
+ p.parseExpected(SyntaxKindOpenParenToken)
+ expression := p.parseModuleSpecifier()
+ p.parseExpected(SyntaxKindCloseParenToken)
+ result := p.factory.NewExternalModuleReference(expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseModuleSpecifier() *Expression {
+ if p.token == SyntaxKindStringLiteral {
+ result := p.parseLiteralExpression()
+ p.internIdentifier(getTextOfIdentifierOrLiteral(result))
+ return result
+ }
+ // We allow arbitrary expressions here, even though the grammar only allows string
+ // literals. We check to ensure that it is only a string literal later in the grammar
+ // check pass.
+ return p.parseExpression()
+}
+
+func (p *Parser) tryParseImportClause(identifier *Node, pos int, isTypeOnly bool, skipJsDocLeadingAsterisks bool) *Node {
+ // ImportDeclaration:
+ // import ImportClause from ModuleSpecifier ;
+ // import ModuleSpecifier;
+ if identifier != nil || p.token == SyntaxKindAsteriskToken || p.token == SyntaxKindOpenBraceToken {
+ importClause := p.parseImportClause(identifier, pos, isTypeOnly, skipJsDocLeadingAsterisks)
+ p.parseExpected(SyntaxKindFromKeyword)
+ return importClause
+ }
+ return nil
+}
+
+func (p *Parser) parseImportClause(identifier *Node, pos int, isTypeOnly bool, skipJsDocLeadingAsterisks bool) *Node {
+ // ImportClause:
+ // ImportedDefaultBinding
+ // NameSpaceImport
+ // NamedImports
+ // ImportedDefaultBinding, NameSpaceImport
+ // ImportedDefaultBinding, NamedImports
+ // If there was no default import or if there is comma token after default import
+ // parse namespace or named imports
+ var namedBindings *Node
+ if identifier == nil || p.parseOptional(SyntaxKindCommaToken) {
+ _ = skipJsDocLeadingAsterisks
+ // !!! if (skipJsDocLeadingAsterisks) scanner.setSkipJsDocLeadingAsterisks(true);
+ if p.token == SyntaxKindAsteriskToken {
+ namedBindings = p.parseNamespaceImport()
+ } else {
+ namedBindings = p.parseNamedImports()
+ }
+ // !!! if (skipJsDocLeadingAsterisks) scanner.setSkipJsDocLeadingAsterisks(false);
+ }
+ result := p.factory.NewImportClause(isTypeOnly, identifier, namedBindings)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseNamespaceImport() *Node {
+ // NameSpaceImport:
+ // * as ImportedBinding
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindAsteriskToken)
+ p.parseExpected(SyntaxKindAsKeyword)
+ name := p.parseIdentifier()
+ result := p.factory.NewNamespaceImport(name)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseNamedImports() *Node {
+ pos := p.nodePos()
+ // NamedImports:
+ // { }
+ // { ImportsList }
+ // { ImportsList, }
+ imports := parseBracketedList(p, PCImportOrExportSpecifiers, p.parseImportSpecifier, SyntaxKindOpenBraceToken, SyntaxKindCloseBraceToken)
+ result := p.factory.NewNamedImports(imports)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseImportSpecifier() *Node {
+ pos := p.nodePos()
+ isTypeOnly, propertyName, name := p.parseImportOrExportSpecifier(SyntaxKindImportSpecifier)
+ var identifierName *Node
+ if name.kind == SyntaxKindIdentifier {
+ identifierName = name
+ } else {
+ p.parseErrorAtRange(p.skipRangeTrivia(name.loc), diagnostics.Identifier_expected)
+ identifierName = p.newIdentifier("")
+ p.finishNode(identifierName, name.Pos())
+ }
+ result := p.factory.NewImportSpecifier(isTypeOnly, propertyName, identifierName)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseImportOrExportSpecifier(kind SyntaxKind) (isTypeOnly bool, propertyName *Node, name *Node) {
+ // ImportSpecifier:
+ // BindingIdentifier
+ // ModuleExportName as BindingIdentifier
+ // ExportSpecifier:
+ // ModuleExportName
+ // ModuleExportName as ModuleExportName
+ // let checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier();
+ // let checkIdentifierStart = scanner.getTokenStart();
+ // let checkIdentifierEnd = scanner.getTokenEnd();
+ canParseAsKeyword := true
+ name = p.parseModuleExportName(false /*disallowKeywords*/)
+ if name.kind == SyntaxKindIdentifier && name.AsIdentifier().text == "type" {
+ // If the first token of an import specifier is 'type', there are a lot of possibilities,
+ // especially if we see 'as' afterwards:
+ //
+ // import { type } from "mod"; - isTypeOnly: false, name: type
+ // import { type as } from "mod"; - isTypeOnly: true, name: as
+ // import { type as as } from "mod"; - isTypeOnly: false, name: as, propertyName: type
+ // import { type as as as } from "mod"; - isTypeOnly: true, name: as, propertyName: as
+ if p.token == SyntaxKindAsKeyword {
+ // { type as ...? }
+ firstAs := p.parseIdentifierName()
+ if p.token == SyntaxKindAsKeyword {
+ // { type as as ...? }
+ secondAs := p.parseIdentifierName()
+ if p.canParseModuleExportName() {
+ // { type as as something }
+ // { type as as "something" }
+ isTypeOnly = true
+ propertyName = firstAs
+ name = p.parseModuleExportName(true /*disallowKeywords*/)
+ canParseAsKeyword = false
+ } else {
+ // { type as as }
+ propertyName = name
+ name = secondAs
+ canParseAsKeyword = false
+ }
+ } else if p.canParseModuleExportName() {
+ // { type as something }
+ // { type as "something" }
+ propertyName = name
+ canParseAsKeyword = false
+ name = p.parseModuleExportName(true /*disallowKeywords*/)
+ } else {
+ // { type as }
+ isTypeOnly = true
+ name = firstAs
+ }
+ } else if p.canParseModuleExportName() {
+ // { type something ...? }
+ // { type "something" ...? }
+ isTypeOnly = true
+ name = p.parseModuleExportName(true /*disallowKeywords*/)
+ }
+ }
+ if canParseAsKeyword && p.token == SyntaxKindAsKeyword {
+ propertyName = name
+ p.parseExpected(SyntaxKindAsKeyword)
+ name = p.parseModuleExportName(kind == SyntaxKindImportSpecifier /*disallowKeywords*/)
+ }
+ return
+}
+
+func (p *Parser) canParseModuleExportName() bool {
+ return tokenIsIdentifierOrKeyword(p.token) || p.token == SyntaxKindStringLiteral
+}
+
+func (p *Parser) parseModuleExportName(disallowKeywords bool) *Node {
+ if p.token == SyntaxKindStringLiteral {
+ return p.parseLiteralExpression()
+ }
+ if disallowKeywords && isKeyword(p.token) && !p.isIdentifier() {
+ p.parseErrorAtCurrentToken(diagnostics.Identifier_expected)
+ }
+ return p.parseIdentifierName()
+}
+
+func (p *Parser) tryParseImportAttributes() *Node {
+ if (p.token == SyntaxKindWithKeyword || p.token == SyntaxKindAssertKeyword) && !p.hasPrecedingLineBreak() {
+ return p.parseImportAttributes(p.token, true /*skipKeyword*/)
+ }
+ return nil
+}
+
+func (p *Parser) parseExportAssignment(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsAwaitContext, true)
+ isExportEquals := false
+ if p.parseOptional(SyntaxKindEqualsToken) {
+ isExportEquals = true
+ } else {
+ p.parseExpected(SyntaxKindDefaultKeyword)
+ }
+ expression := p.parseAssignmentExpressionOrHigher()
+ p.parseSemicolon()
+ p.contextFlags = saveContextFlags
+ result := p.factory.NewExportAssignment(modifiers, isExportEquals, expression)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseNamespaceExportDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ p.parseExpected(SyntaxKindAsKeyword)
+ p.parseExpected(SyntaxKindNamespaceKeyword)
+ name := p.parseIdentifier()
+ p.parseSemicolon()
+ // NamespaceExportDeclaration nodes cannot have decorators or modifiers, we attach them here so we can report them in the grammar checker
+ result := p.factory.NewNamespaceExportDeclaration(modifiers, name)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseExportDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsAwaitContext, true)
+ var exportClause *Node
+ var moduleSpecifier *Expression
+ var attributes *Node
+ isTypeOnly := p.parseOptional(SyntaxKindTypeKeyword)
+ namespaceExportPos := p.nodePos()
+ if p.parseOptional(SyntaxKindAsteriskToken) {
+ if p.parseOptional(SyntaxKindAsKeyword) {
+ exportClause = p.parseNamespaceExport(namespaceExportPos)
+ }
+ p.parseExpected(SyntaxKindFromKeyword)
+ moduleSpecifier = p.parseModuleSpecifier()
+ } else {
+ exportClause = p.parseNamedExports()
+ // It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios,
+ // the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`)
+ // If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect.
+ if p.token == SyntaxKindFromKeyword || (p.token == SyntaxKindStringLiteral && !p.hasPrecedingLineBreak()) {
+ p.parseExpected(SyntaxKindFromKeyword)
+ moduleSpecifier = p.parseModuleSpecifier()
+ }
+ }
+ if moduleSpecifier != nil && (p.token == SyntaxKindWithKeyword || p.token == SyntaxKindAssertKeyword) && !p.hasPrecedingLineBreak() {
+ attributes = p.parseImportAttributes(p.token, true /*skipKeyword*/)
+ }
+ p.parseSemicolon()
+ p.contextFlags = saveContextFlags
+ result := p.factory.NewExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, attributes)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseNamespaceExport(pos int) *Node {
+ result := p.factory.NewNamespaceExport(p.parseModuleExportName(false /*disallowKeywords*/))
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseNamedExports() *Node {
+ pos := p.nodePos()
+ // NamedImports:
+ // { }
+ // { ImportsList }
+ // { ImportsList, }
+ exports := parseBracketedList(p, PCImportOrExportSpecifiers, p.parseExportSpecifier, SyntaxKindOpenBraceToken, SyntaxKindCloseBraceToken)
+ result := p.factory.NewNamedExports(exports)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseExportSpecifier() *Node {
+ pos := p.nodePos()
+ isTypeOnly, propertyName, name := p.parseImportOrExportSpecifier(SyntaxKindExportSpecifier)
+ result := p.factory.NewExportSpecifier(isTypeOnly, propertyName, name)
+ p.finishNode(result, pos)
+ return result
+}
+
+// TYPES
+
+func (p *Parser) parseType() *TypeNode {
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsTypeExcludesFlags, false)
+ var typeNode *TypeNode
+ if p.isStartOfFunctionTypeOrConstructorType() {
+ typeNode = p.parseFunctionOrConstructorType()
+ } else {
+ pos := p.nodePos()
+ typeNode = p.parseUnionTypeOrHigher()
+ if !p.inDisallowConditionalTypesContext() && !p.hasPrecedingLineBreak() && p.parseOptional(SyntaxKindExtendsKeyword) {
+ // The type following 'extends' is not permitted to be another conditional type
+ extendsType := doInContext(p, NodeFlagsDisallowConditionalTypesContext, true, p.parseType)
+ p.parseExpected(SyntaxKindQuestionToken)
+ trueType := doInContext(p, NodeFlagsDisallowConditionalTypesContext, false, p.parseType)
+ p.parseExpected(SyntaxKindColonToken)
+ falseType := doInContext(p, NodeFlagsDisallowConditionalTypesContext, false, p.parseType)
+ conditionalType := p.factory.NewConditionalTypeNode(typeNode, extendsType, trueType, falseType)
+ p.finishNode(conditionalType, pos)
+ typeNode = conditionalType
+ }
+ }
+ p.contextFlags = saveContextFlags
+ return typeNode
+}
+
+func (p *Parser) parseUnionTypeOrHigher() *TypeNode {
+ return p.parseUnionOrIntersectionType(SyntaxKindBarToken, p.parseIntersectionTypeOrHigher)
+}
+
+func (p *Parser) parseIntersectionTypeOrHigher() *TypeNode {
+ return p.parseUnionOrIntersectionType(SyntaxKindAmpersandToken, p.parseTypeOperatorOrHigher)
+}
+
+func (p *Parser) parseUnionOrIntersectionType(operator SyntaxKind, parseConstituentType func() *TypeNode) *TypeNode {
+ pos := p.nodePos()
+ isUnionType := operator == SyntaxKindBarToken
+ hasLeadingOperator := p.parseOptional(operator)
+ var typeNode *TypeNode
+ if hasLeadingOperator {
+ typeNode = p.parseFunctionOrConstructorTypeToError(isUnionType, parseConstituentType)
+ } else {
+ typeNode = parseConstituentType()
+ }
+ if p.token == operator || hasLeadingOperator {
+ types := []*TypeNode{typeNode}
+ for p.parseOptional(operator) {
+ types = append(types, p.parseFunctionOrConstructorTypeToError(isUnionType, parseConstituentType))
+ }
+ typeNode = p.createUnionOrIntersectionTypeNode(operator, types)
+ p.finishNode(typeNode, pos)
+ }
+ return typeNode
+}
+
+func (p *Parser) createUnionOrIntersectionTypeNode(operator SyntaxKind, types []*TypeNode) *Node {
+ switch operator {
+ case SyntaxKindBarToken:
+ return p.factory.NewUnionTypeNode(types)
+ case SyntaxKindAmpersandToken:
+ return p.factory.NewIntersectionTypeNode(types)
+ default:
+ panic("Unhandled case in createUnionOrIntersectionType")
+ }
+}
+
+func (p *Parser) parseTypeOperatorOrHigher() *TypeNode {
+ operator := p.token
+ switch operator {
+ case SyntaxKindKeyOfKeyword, SyntaxKindUniqueKeyword, SyntaxKindReadonlyKeyword:
+ return p.parseTypeOperator(operator)
+ case SyntaxKindInferKeyword:
+ return p.parseInferType()
+ }
+ return doInContext(p, NodeFlagsDisallowConditionalTypesContext, false, p.parsePostfixTypeOrHigher)
+}
+
+func (p *Parser) parseTypeOperator(operator SyntaxKind) *Node {
+ pos := p.nodePos()
+ p.parseExpected(operator)
+ result := p.factory.NewTypeOperatorNode(operator, p.parseTypeOperatorOrHigher())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseInferType() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindInferKeyword)
+ result := p.factory.NewInferTypeNode(p.parseTypeParameterOfInferType())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTypeParameterOfInferType() *Node {
+ pos := p.nodePos()
+ name := p.parseIdentifier()
+ constraint := p.tryParseConstraintOfInferType()
+ result := p.factory.NewTypeParameterDeclaration(nil /*modifiers*/, name, constraint, nil /*defaultType*/)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) tryParseConstraintOfInferType() *Node {
+ state := p.mark()
+ if p.parseOptional(SyntaxKindExtendsKeyword) {
+ constraint := doInContext(p, NodeFlagsDisallowConditionalTypesContext, true, p.parseType)
+ if p.inDisallowConditionalTypesContext() || p.token != SyntaxKindQuestionToken {
+ return constraint
+ }
+ }
+ p.rewind(state)
+ return nil
+}
+
+func (p *Parser) parsePostfixTypeOrHigher() *Node {
+ pos := p.nodePos()
+ typeNode := p.parseNonArrayType()
+ for !p.hasPrecedingLineBreak() {
+ switch p.token {
+ case SyntaxKindExclamationToken:
+ p.nextToken()
+ typeNode = p.factory.NewJSDocNonNullableType(typeNode, true /*postfix*/)
+ p.finishNode(typeNode, pos)
+ case SyntaxKindQuestionToken:
+ // If next token is start of a type we have a conditional type
+ if p.lookAhead(p.nextIsStartOfType) {
+ return typeNode
+ }
+ p.nextToken()
+ typeNode = p.factory.NewJSDocNullableType(typeNode, true /*postfix*/)
+ p.finishNode(typeNode, pos)
+ case SyntaxKindOpenBracketToken:
+ p.parseExpected(SyntaxKindOpenBracketToken)
+ if p.isStartOfType(false /*isStartOfParameter*/) {
+ indexType := p.parseType()
+ p.parseExpected(SyntaxKindCloseBracketToken)
+ typeNode = p.factory.NewIndexedAccessTypeNode(typeNode, indexType)
+ p.finishNode(typeNode, pos)
+ } else {
+ p.parseExpected(SyntaxKindCloseBracketToken)
+ typeNode = p.factory.NewArrayTypeNode(typeNode)
+ p.finishNode(typeNode, pos)
+ }
+ default:
+ return typeNode
+ }
+ }
+ return typeNode
+}
+
+func (p *Parser) nextIsStartOfType() bool {
+ p.nextToken()
+ return p.isStartOfType(false /*inStartOfParameter*/)
+}
+
+func (p *Parser) parseNonArrayType() *Node {
+ switch p.token {
+ case SyntaxKindAnyKeyword, SyntaxKindUnknownKeyword, SyntaxKindStringKeyword, SyntaxKindNumberKeyword, SyntaxKindBigIntKeyword,
+ SyntaxKindSymbolKeyword, SyntaxKindBooleanKeyword, SyntaxKindUndefinedKeyword, SyntaxKindNeverKeyword, SyntaxKindObjectKeyword:
+ state := p.mark()
+ keywordTypeNode := p.parseKeywordTypeNode()
+ // If these are followed by a dot then parse these out as a dotted type reference instead
+ if p.token != SyntaxKindDotToken {
+ return keywordTypeNode
+ }
+ p.rewind(state)
+ return p.parseTypeReference()
+ // !!!
+ // case SyntaxKindAsteriskEqualsToken:
+ // // If there is '*=', treat it as * followed by postfix =
+ // p.scanner.reScanAsteriskEqualsToken()
+ // fallthrough
+ // case SyntaxKindAsteriskToken:
+ // return p.parseJSDocAllType()
+ // case SyntaxKindQuestionQuestionToken:
+ // // If there is '??', treat it as prefix-'?' in JSDoc type.
+ // p.scanner.reScanQuestionToken()
+ // fallthrough
+ // case SyntaxKindQuestionToken:
+ // return p.parseJSDocUnknownOrNullableType()
+ // case SyntaxKindFunctionKeyword:
+ // return p.parseJSDocFunctionType()
+ // case SyntaxKindExclamationToken:
+ // return p.parseJSDocNonNullableType()
+ case SyntaxKindNoSubstitutionTemplateLiteral, SyntaxKindStringLiteral, SyntaxKindNumericLiteral, SyntaxKindBigintLiteral, SyntaxKindTrueKeyword,
+ SyntaxKindFalseKeyword, SyntaxKindNullKeyword:
+ return p.parseLiteralTypeNode(false /*negative*/)
+ case SyntaxKindMinusToken:
+ if p.lookAhead(p.nextTokenIsNumericOrBigIntLiteral) {
+ return p.parseLiteralTypeNode(true /*negative*/)
+ }
+ return p.parseTypeReference()
+ case SyntaxKindVoidKeyword:
+ return p.parseKeywordTypeNode()
+ case SyntaxKindThisKeyword:
+ thisKeyword := p.parseThisTypeNode()
+ if p.token == SyntaxKindIsKeyword && !p.hasPrecedingLineBreak() {
+ return p.parseThisTypePredicate(thisKeyword)
+ }
+ return thisKeyword
+ case SyntaxKindTypeOfKeyword:
+ if p.lookAhead(p.nextIsStartOfTypeOfImportType) {
+ return p.parseImportType()
+ }
+ return p.parseTypeQuery()
+ case SyntaxKindOpenBraceToken:
+ if p.lookAhead(p.nextIsStartOfMappedType) {
+ return p.parseMappedType()
+ }
+ return p.parseTypeLiteral()
+ case SyntaxKindOpenBracketToken:
+ return p.parseTupleType()
+ case SyntaxKindOpenParenToken:
+ return p.parseParenthesizedType()
+ case SyntaxKindImportKeyword:
+ return p.parseImportType()
+ case SyntaxKindAssertsKeyword:
+ if p.lookAhead(p.nextTokenIsIdentifierOrKeywordOnSameLine) {
+ return p.parseAssertsTypePredicate()
+ }
+ return p.parseTypeReference()
+ case SyntaxKindTemplateHead:
+ return p.parseTemplateType()
+ default:
+ return p.parseTypeReference()
+ }
+}
+
+func (p *Parser) parseKeywordTypeNode() *Node {
+ pos := p.nodePos()
+ result := p.factory.NewKeywordTypeNode(p.token)
+ p.nextToken()
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseThisTypeNode() *Node {
+ pos := p.nodePos()
+ p.nextToken()
+ result := p.factory.NewThisTypeNode()
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseThisTypePredicate(lhs *Node) *Node {
+ p.nextToken()
+ result := p.factory.NewTypePredicateNode(nil /*assertsModifier*/, lhs, p.parseType())
+ p.finishNode(result, lhs.Pos())
+ return result
+}
+
+func (p *Parser) parseLiteralTypeNode(negative bool) *Node {
+ pos := p.nodePos()
+ if negative {
+ p.nextToken()
+ }
+ var expression *Expression
+ if p.token == SyntaxKindTrueKeyword || p.token == SyntaxKindFalseKeyword || p.token == SyntaxKindNullKeyword {
+ expression = p.parseKeywordExpression()
+ } else {
+ expression = p.parseLiteralExpression()
+ }
+ if negative {
+ expression = p.factory.NewPrefixUnaryExpression(SyntaxKindMinusToken, expression)
+ p.finishNode(expression, pos)
+ }
+ result := p.factory.NewLiteralTypeNode(expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTypeReference() *Node {
+ pos := p.nodePos()
+ result := p.factory.NewTypeReferenceNode(p.parseEntityNameOfTypeReference(), p.parseTypeArgumentsOfTypeReference())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseEntityNameOfTypeReference() *Node {
+ return p.parseEntityName(true /*allowReservedWords*/, diagnostics.Type_expected)
+}
+
+func (p *Parser) parseEntityName(allowReservedWords bool, diagnosticMessage *diagnostics.Message) *Node {
+ pos := p.nodePos()
+ var entity *Node
+ if allowReservedWords {
+ entity = p.parseIdentifierNameWithDiagnostic(diagnosticMessage)
+ } else {
+ entity = p.parseIdentifierWithDiagnostic(diagnosticMessage, nil)
+ }
+ for p.parseOptional(SyntaxKindDotToken) {
+ if p.token == SyntaxKindLessThanToken {
+ // The entity is part of a JSDoc-style generic. We will use the gap between `typeName` and
+ // `typeArguments` to report it as a grammar error in the checker.
+ break
+ }
+ entity = p.factory.NewQualifiedName(entity, p.parseRightSideOfDot(allowReservedWords, false /*allowPrivateIdentifiers*/, true /*allowUnicodeEscapeSequenceInIdentifierName*/))
+ p.finishNode(entity, pos)
+ }
+ return entity
+}
+
+func (p *Parser) parseRightSideOfDot(allowIdentifierNames bool, allowPrivateIdentifiers bool, allowUnicodeEscapeSequenceInIdentifierName bool) *Node {
+ // Technically a keyword is valid here as all identifiers and keywords are identifier names.
+ // However, often we'll encounter this in error situations when the identifier or keyword
+ // is actually starting another valid construct.
+ //
+ // So, we check for the following specific case:
+ //
+ // name.
+ // identifierOrKeyword identifierNameOrKeyword
+ //
+ // Note: the newlines are important here. For example, if that above code
+ // were rewritten into:
+ //
+ // name.identifierOrKeyword
+ // identifierNameOrKeyword
+ //
+ // Then we would consider it valid. That's because ASI would take effect and
+ // the code would be implicitly: "name.identifierOrKeyword; identifierNameOrKeyword".
+ // In the first case though, ASI will not take effect because there is not a
+ // line terminator after the identifier or keyword.
+ if p.hasPrecedingLineBreak() && tokenIsIdentifierOrKeyword(p.token) && p.lookAhead(p.nextTokenIsIdentifierOrKeywordOnSameLine) {
+ // Report that we need an identifier. However, report it right after the dot,
+ // and not on the next token. This is because the next token might actually
+ // be an identifier and the error would be quite confusing.
+ p.parseErrorAt(p.nodePos(), p.nodePos(), diagnostics.Identifier_expected)
+ return p.createMissingIdentifier()
+ }
+ if p.token == SyntaxKindPrivateIdentifier {
+ node := p.parsePrivateIdentifier()
+ if allowPrivateIdentifiers {
+ return node
+ }
+ p.parseErrorAt(p.nodePos(), p.nodePos(), diagnostics.Identifier_expected)
+ return p.createMissingIdentifier()
+ }
+ if allowIdentifierNames {
+ if allowUnicodeEscapeSequenceInIdentifierName {
+ return p.parseIdentifierName()
+ }
+ return p.parseIdentifierNameErrorOnUnicodeEscapeSequence()
+ }
+
+ return p.parseIdentifier()
+}
+
+func (p *Parser) newIdentifier(text string) *Node {
+ return p.factory.NewIdentifier(text)
+}
+
+func (p *Parser) createMissingIdentifier() *Node {
+ result := p.newIdentifier("")
+ p.finishNode(result, p.nodePos())
+ return result
+}
+
+func (p *Parser) parsePrivateIdentifier() *Node {
+ pos := p.nodePos()
+ text := p.scanner.TokenValue()
+ p.internIdentifier(text)
+ p.nextToken()
+ result := p.factory.NewPrivateIdentifier(text)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) reScanLessThanToken() SyntaxKind {
+ p.token = p.scanner.ReScanLessThanToken()
+ return p.token
+}
+
+func (p *Parser) reScanGreaterThanToken() SyntaxKind {
+ p.token = p.scanner.ReScanGreaterThanToken()
+ return p.token
+}
+
+func (p *Parser) reScanSlashToken() SyntaxKind {
+ p.token = p.scanner.ReScanSlashToken()
+ return p.token
+}
+
+func (p *Parser) reScanTemplateToken(isTaggedTemplate bool) SyntaxKind {
+ p.token = p.scanner.ReScanTemplateToken(isTaggedTemplate)
+ return p.token
+}
+
+func (p *Parser) parseTypeArgumentsOfTypeReference() *Node {
+ if !p.hasPrecedingLineBreak() && p.reScanLessThanToken() == SyntaxKindLessThanToken {
+ return p.parseTypeArguments()
+ }
+ return nil
+}
+
+func (p *Parser) parseTypeArguments() *Node {
+ if p.token == SyntaxKindLessThanToken {
+ pos := p.nodePos()
+ typeArguments := parseBracketedList(p, PCTypeArguments, p.parseType, SyntaxKindLessThanToken, SyntaxKindGreaterThanToken)
+ if typeArguments != nil {
+ result := p.factory.NewTypeArgumentList(typeArguments)
+ p.finishNode(result, pos)
+ return result
+ }
+ }
+ return nil
+}
+
+func (p *Parser) nextIsStartOfTypeOfImportType() bool {
+ p.nextToken()
+ return p.token == SyntaxKindImportKeyword
+}
+
+func (p *Parser) parseImportType() *Node {
+ p.sourceFlags |= NodeFlagsPossiblyContainsDynamicImport
+ pos := p.nodePos()
+ isTypeOf := p.parseOptional(SyntaxKindTypeOfKeyword)
+ p.parseExpected(SyntaxKindImportKeyword)
+ p.parseExpected(SyntaxKindOpenParenToken)
+ typeNode := p.parseType()
+ var attributes *Node
+ if p.parseOptional(SyntaxKindCommaToken) {
+ openBracePosition := p.scanner.TokenStart()
+ p.parseExpected(SyntaxKindOpenBraceToken)
+ currentToken := p.token
+ if currentToken == SyntaxKindWithKeyword || currentToken == SyntaxKindAssertKeyword {
+ p.nextToken()
+ } else {
+ p.parseErrorAtCurrentToken(diagnostics.X_0_expected, TokenToString(SyntaxKindWithKeyword))
+ }
+ p.parseExpected(SyntaxKindColonToken)
+ attributes = p.parseImportAttributes(currentToken, true /*skipKeyword*/)
+ if !p.parseExpected(SyntaxKindCloseBraceToken) {
+ if len(p.diagnostics) != 0 {
+ lastDiagnostic := p.diagnostics[len(p.diagnostics)-1]
+ if lastDiagnostic.Code() == diagnostics.X_0_expected.Code() {
+ related := NewDiagnostic(nil, NewTextRange(openBracePosition, openBracePosition+1), diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}")
+ addRelatedInfo(lastDiagnostic, related)
+ }
+ }
+ }
+ }
+ p.parseExpected(SyntaxKindCloseParenToken)
+ var qualifier *Node
+ if p.parseOptional(SyntaxKindDotToken) {
+ qualifier = p.parseEntityNameOfTypeReference()
+ }
+ typeArguments := p.parseTypeArgumentsOfTypeReference()
+ result := p.factory.NewImportTypeNode(isTypeOf, typeNode, attributes, qualifier, typeArguments)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseImportAttribute() *Node {
+ pos := p.nodePos()
+ var name *Node
+ if tokenIsIdentifierOrKeyword(p.token) {
+ name = p.parseIdentifierName()
+ } else if p.token == SyntaxKindStringLiteral {
+ name = p.parseLiteralExpression()
+ }
+ if name != nil {
+ p.parseExpected(SyntaxKindColonToken)
+ } else {
+ p.parseErrorAtCurrentToken(diagnostics.Identifier_or_string_literal_expected)
+ }
+ value := p.parseAssignmentExpressionOrHigher()
+ result := p.factory.NewImportAttribute(name, value)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseImportAttributes(token SyntaxKind, skipKeyword bool) *Node {
+ pos := p.nodePos()
+ if !skipKeyword {
+ p.parseExpected(token)
+ }
+ var elements []*Node
+ var multiLine bool
+ openBracePosition := p.scanner.TokenStart()
+ if p.parseExpected(SyntaxKindOpenBraceToken) {
+ multiLine = p.hasPrecedingLineBreak()
+ elements = parseDelimitedList(p, PCImportAttributes, p.parseImportAttribute)
+ if !p.parseExpected(SyntaxKindCloseBraceToken) {
+ if len(p.diagnostics) != 0 {
+ lastDiagnostic := p.diagnostics[len(p.diagnostics)-1]
+ if lastDiagnostic.Code() == diagnostics.X_0_expected.Code() {
+ related := NewDiagnostic(nil, NewTextRange(openBracePosition, openBracePosition+1), diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}")
+ addRelatedInfo(lastDiagnostic, related)
+ }
+ }
+ }
+ }
+ result := p.factory.NewImportAttributes(token, elements, multiLine)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTypeQuery() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindTypeOfKeyword)
+ entityName := p.parseEntityName(true /*allowReservedWords*/, nil)
+ // Make sure we perform ASI to prevent parsing the next line's type arguments as part of an instantiation expression
+ var typeArguments *Node
+ if !p.hasPrecedingLineBreak() {
+ typeArguments = p.parseTypeArguments()
+ }
+ result := p.factory.NewTypeQueryNode(entityName, typeArguments)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) nextIsStartOfMappedType() bool {
+ p.nextToken()
+ if p.token == SyntaxKindPlusToken || p.token == SyntaxKindMinusToken {
+ return p.nextToken() == SyntaxKindReadonlyKeyword
+ }
+ if p.token == SyntaxKindReadonlyKeyword {
+ p.nextToken()
+ }
+ return p.token == SyntaxKindOpenBracketToken && p.nextTokenIsIdentifier() && p.nextToken() == SyntaxKindInKeyword
+}
+
+func (p *Parser) parseMappedType() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindOpenBraceToken)
+ var readonlyToken *Node // ReadonlyKeyword | PlusToken | MinusToken
+ if p.token == SyntaxKindReadonlyKeyword || p.token == SyntaxKindPlusToken || p.token == SyntaxKindMinusToken {
+ readonlyToken = p.parseTokenNode()
+ if readonlyToken.kind != SyntaxKindReadonlyKeyword {
+ p.parseExpected(SyntaxKindReadonlyKeyword)
+ }
+ }
+ p.parseExpected(SyntaxKindOpenBracketToken)
+ typeParameter := p.parseMappedTypeParameter()
+ var nameType *TypeNode
+ if p.parseOptional(SyntaxKindAsKeyword) {
+ nameType = p.parseType()
+ }
+ p.parseExpected(SyntaxKindCloseBracketToken)
+ var questionToken *Node // QuestionToken | PlusToken | MinusToken
+ if p.token == SyntaxKindQuestionToken || p.token == SyntaxKindPlusToken || p.token == SyntaxKindMinusToken {
+ questionToken = p.parseTokenNode()
+ if questionToken.kind != SyntaxKindQuestionToken {
+ p.parseExpected(SyntaxKindQuestionToken)
+ }
+ }
+ typeNode := p.parseTypeAnnotation()
+ p.parseSemicolon()
+ members := parseList(p, PCTypeMembers, p.parseTypeMember)
+ p.parseExpected(SyntaxKindCloseBraceToken)
+ result := p.factory.NewMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, typeNode, members)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseMappedTypeParameter() *Node {
+ pos := p.nodePos()
+ name := p.parseIdentifierName()
+ p.parseExpected(SyntaxKindInKeyword)
+ typeNode := p.parseType()
+ result := p.factory.NewTypeParameterDeclaration(nil /*modifiers*/, name, typeNode, nil /*defaultType*/)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTypeMember() *Node {
+ if p.token == SyntaxKindOpenParenToken || p.token == SyntaxKindLessThanToken {
+ return p.parseSignatureMember(SyntaxKindCallSignature)
+ }
+ if p.token == SyntaxKindNewKeyword && p.lookAhead(p.nextTokenIsOpenParenOrLessThan) {
+ return p.parseSignatureMember(SyntaxKindConstructSignature)
+ }
+ pos := p.nodePos()
+ hasJSDoc := p.hasPrecedingJSDocComment()
+ modifiers := p.parseModifiers()
+ if p.parseContextualModifier(SyntaxKindGetKeyword) {
+ return p.parseAccessorDeclaration(pos, hasJSDoc, modifiers, SyntaxKindGetAccessor, SignatureFlagsType)
+ }
+ if p.parseContextualModifier(SyntaxKindSetKeyword) {
+ return p.parseAccessorDeclaration(pos, hasJSDoc, modifiers, SyntaxKindSetAccessor, SignatureFlagsType)
+ }
+ if p.isIndexSignature() {
+ return p.parseIndexSignatureDeclaration(pos, hasJSDoc, modifiers)
+ }
+ return p.parsePropertyOrMethodSignature(pos, hasJSDoc, modifiers)
+}
+
+func (p *Parser) nextTokenIsOpenParenOrLessThan() bool {
+ p.nextToken()
+ return p.token == SyntaxKindOpenParenToken || p.token == SyntaxKindLessThanToken
+}
+
+func (p *Parser) parseSignatureMember(kind SyntaxKind) *Node {
+ pos := p.nodePos()
+ // hasJSDoc := p.hasPrecedingJSDocComment()
+ if kind == SyntaxKindConstructSignature {
+ p.parseExpected(SyntaxKindNewKeyword)
+ }
+ typeParameters := p.parseTypeParameters()
+ parameters := p.parseParameters(SignatureFlagsType)
+ typeNode := p.parseReturnType(SyntaxKindColonToken /*isType*/, true)
+ p.parseTypeMemberSemicolon()
+ var result *Node
+ if kind == SyntaxKindCallSignature {
+ result = p.factory.NewCallSignatureDeclaration(typeParameters, parameters, typeNode)
+ } else {
+ result = p.factory.NewConstructSignatureDeclaration(typeParameters, parameters, typeNode)
+ }
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTypeParameters() *Node {
+ if p.token == SyntaxKindLessThanToken {
+ pos := p.nodePos()
+ typeParameters := parseBracketedList(p, PCTypeParameters, p.parseTypeParameter, SyntaxKindLessThanToken, SyntaxKindGreaterThanToken)
+ if typeParameters != nil {
+ result := p.factory.NewTypeParameterList(typeParameters)
+ p.finishNode(result, pos)
+ return result
+ }
+ }
+ return nil
+}
+
+func (p *Parser) parseTypeParameter() *Node {
+ pos := p.nodePos()
+ modifiers := p.parseModifiersWithOptions(false /*allowDecorators*/, true /*permitConstAsModifier*/, false /*stopOnStartOfClassStaticBlock*/)
+ name := p.parseIdentifier()
+ var constraint *TypeNode
+ var expression *Expression
+ if p.parseOptional(SyntaxKindExtendsKeyword) {
+ // It's not uncommon for people to write improper constraints to a generic. If the
+ // user writes a constraint that is an expression and not an actual type, then parse
+ // it out as an expression (so we can recover well), but report that a type is needed
+ // instead.
+ if p.isStartOfType(false /*inStartOfParameter*/) || !p.isStartOfExpression() {
+ constraint = p.parseType()
+ } else {
+ // It was not a type, and it looked like an expression. Parse out an expression
+ // here so we recover well. Note: it is important that we call parseUnaryExpression
+ // and not parseExpression here. If the user has:
+ //
+ //
+ //
+ // We do *not* want to consume the `>` as we're consuming the expression for "".
+ expression = p.parseUnaryExpressionOrHigher()
+ }
+ }
+ var defaultType *TypeNode
+ if p.parseOptional(SyntaxKindEqualsToken) {
+ defaultType = p.parseType()
+ }
+ result := p.factory.NewTypeParameterDeclaration(modifiers, name, constraint, defaultType)
+ result.AsTypeParameter().expression = expression
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseParameters(flags SignatureFlags) []*Node {
+ // FormalParameters [Yield,Await]: (modified)
+ // [empty]
+ // FormalParameterList[?Yield,Await]
+ //
+ // FormalParameter[Yield,Await]: (modified)
+ // BindingElement[?Yield,Await]
+ //
+ // BindingElement [Yield,Await]: (modified)
+ // SingleNameBinding[?Yield,?Await]
+ // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
+ //
+ // SingleNameBinding [Yield,Await]:
+ // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
+ if p.parseExpected(SyntaxKindOpenParenToken) {
+ parameters := p.parseParametersWorker(flags, true /*allowAmbiguity*/)
+ p.parseExpected(SyntaxKindCloseParenToken)
+ return parameters
+ }
+ return nil
+}
+
+func (p *Parser) parseParametersWorker(flags SignatureFlags, allowAmbiguity bool) []*Node {
+ // FormalParameters [Yield,Await]: (modified)
+ // [empty]
+ // FormalParameterList[?Yield,Await]
+ //
+ // FormalParameter[Yield,Await]: (modified)
+ // BindingElement[?Yield,Await]
+ //
+ // BindingElement [Yield,Await]: (modified)
+ // SingleNameBinding[?Yield,?Await]
+ // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
+ //
+ // SingleNameBinding [Yield,Await]:
+ // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
+ inAwaitContext := p.contextFlags&NodeFlagsAwaitContext != 0
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsYieldContext, flags&SignatureFlagsYield != 0)
+ p.setContextFlags(NodeFlagsAwaitContext, flags&SignatureFlagsAwait != 0)
+ // const parameters = flags & SignatureFlags.JSDoc ?
+ // parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) :
+ parameters := parseDelimitedList(p, PCParameters, func() *Node {
+ return p.parseParameterWithOptions(inAwaitContext, allowAmbiguity)
+ })
+ p.contextFlags = saveContextFlags
+ return parameters
+
+}
+
+func (p *Parser) parseParameter() *Node {
+ return p.parseParameterWithOptions(false /*inOuterAwaitContext*/, true /*allowAmbiguity*/)
+}
+
+func (p *Parser) parseParameterWithOptions(inOuterAwaitContext bool, allowAmbiguity bool) *Node {
+ pos := p.nodePos()
+ // hasJSDoc := p.hasPrecedingJSDocComment()
+ // FormalParameter [Yield,Await]:
+ // BindingElement[?Yield,?Await]
+ // Decorators are parsed in the outer [Await] context, the rest of the parameter is parsed in the function's [Await] context.
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsAwaitContext, inOuterAwaitContext)
+ modifiers := p.parseModifiersWithOptions(true /*allowDecorators*/, false /*permitConstAsModifier*/, false /*stopOnStartOfClassStaticBlock*/)
+ p.contextFlags = saveContextFlags
+ if p.token == SyntaxKindThisKeyword {
+ result := p.factory.NewParameterDeclaration(
+ modifiers,
+ nil, /*dotDotDotToken*/
+ p.createIdentifier(true /*isIdentifier*/),
+ nil, /*questionToken*/
+ p.parseTypeAnnotation(),
+ nil /*initializer*/)
+ if modifiers != nil {
+ p.parseErrorAtRange(modifiers.loc, diagnostics.Neither_decorators_nor_modifiers_may_be_applied_to_this_parameters)
+ }
+ p.finishNode(result, pos)
+ return result
+ }
+ dotDotDotToken := p.parseOptionalToken(SyntaxKindDotDotDotToken)
+ if !allowAmbiguity && !p.isParameterNameStart() {
+ return nil
+ }
+ result := p.factory.NewParameterDeclaration(
+ modifiers,
+ dotDotDotToken,
+ p.parseNameOfParameter(modifiers),
+ p.parseOptionalToken(SyntaxKindQuestionToken),
+ p.parseTypeAnnotation(),
+ p.parseInitializer())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) isParameterNameStart() bool {
+ // Be permissive about await and yield by calling isBindingIdentifier instead of isIdentifier; disallowing
+ // them during a speculative parse leads to many more follow-on errors than allowing the function to parse then later
+ // complaining about the use of the keywords.
+ return p.isBindingIdentifier() || p.token == SyntaxKindOpenBracketToken || p.token == SyntaxKindOpenBraceToken
+}
+
+func (p *Parser) parseNameOfParameter(modifiers *Node) *Node {
+ // FormalParameter [Yield,Await]:
+ // BindingElement[?Yield,?Await]
+ name := p.parseIdentifierOrPatternWithDiagnostic(diagnostics.Private_identifiers_cannot_be_used_as_parameters)
+ if name.loc.Len() == 0 && modifiers == nil && isModifierKind(p.token) {
+ // in cases like
+ // 'use strict'
+ // function foo(static)
+ // isParameter('static') == true, because of isModifier('static')
+ // however 'static' is not a legal identifier in a strict mode.
+ // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined)
+ // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM)
+ // to avoid this we'll advance cursor to the next token.
+ p.nextToken()
+ }
+ return name
+}
+
+func (p *Parser) parseReturnType(returnToken SyntaxKind, isType bool) *TypeNode {
+ if p.shouldParseReturnType(returnToken, isType) {
+ return doInContext(p, NodeFlagsDisallowConditionalTypesContext, false, p.parseTypeOrTypePredicate)
+ }
+ return nil
+}
+
+func (p *Parser) shouldParseReturnType(returnToken SyntaxKind, isType bool) bool {
+ if returnToken == SyntaxKindEqualsGreaterThanToken {
+ p.parseExpected(returnToken)
+ return true
+ } else if p.parseOptional(SyntaxKindColonToken) {
+ return true
+ } else if isType && p.token == SyntaxKindEqualsGreaterThanToken {
+ // This is easy to get backward, especially in type contexts, so parse the type anyway
+ p.parseErrorAtCurrentToken(diagnostics.X_0_expected, TokenToString(SyntaxKindColonToken))
+ p.nextToken()
+ return true
+ }
+ return false
+}
+
+func (p *Parser) parseTypeOrTypePredicate() *TypeNode {
+ if p.isIdentifier() {
+ state := p.mark()
+ pos := p.nodePos()
+ id := p.parseIdentifier()
+ if p.token == SyntaxKindIsKeyword && !p.hasPrecedingLineBreak() {
+ p.nextToken()
+ result := p.factory.NewTypePredicateNode(nil /*assertsModifier*/, id, p.parseType())
+ p.finishNode(result, pos)
+ return result
+ }
+ p.rewind(state)
+ }
+ return p.parseType()
+}
+
+func (p *Parser) parseTypeMemberSemicolon() {
+ // We allow type members to be separated by commas or (possibly ASI) semicolons.
+ // First check if it was a comma. If so, we're done with the member.
+ if p.parseOptional(SyntaxKindCommaToken) {
+ return
+ }
+ // Didn't have a comma. We must have a (possible ASI) semicolon.
+ p.parseSemicolon()
+}
+
+func (p *Parser) parseAccessorDeclaration(pos int, hasJSDoc bool, modifiers *Node, kind SyntaxKind, flags SignatureFlags) *Node {
+ name := p.parsePropertyName()
+ typeParameters := p.parseTypeParameters()
+ parameters := p.parseParameters(SignatureFlagsNone)
+ returnType := p.parseReturnType(SyntaxKindColonToken, false /*isType*/)
+ body := p.parseFunctionBlockOrSemicolon(flags, nil /*diagnosticMessage*/)
+ var result *Node
+ // Keep track of `typeParameters` (for both) and `type` (for setters) if they were parsed those indicate grammar errors
+ if kind == SyntaxKindGetAccessor {
+ result = p.factory.NewGetAccessorDeclaration(modifiers, name, typeParameters, parameters, returnType, body)
+ } else {
+ result = p.factory.NewSetAccessorDeclaration(modifiers, name, typeParameters, parameters, returnType, body)
+ }
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parsePropertyName() *Node {
+ return p.parsePropertyNameWorker(true /*allowComputedPropertyNames*/)
+}
+
+func (p *Parser) parsePropertyNameWorker(allowComputedPropertyNames bool) *Node {
+ if p.token == SyntaxKindStringLiteral || p.token == SyntaxKindNumericLiteral || p.token == SyntaxKindBigintLiteral {
+ literal := p.parseLiteralExpression()
+ p.internIdentifier(getTextOfIdentifierOrLiteral(literal))
+ return literal
+ }
+ if allowComputedPropertyNames && p.token == SyntaxKindOpenBracketToken {
+ return p.parseComputedPropertyName()
+ }
+ if p.token == SyntaxKindPrivateIdentifier {
+ return p.parsePrivateIdentifier()
+ }
+ return p.parseIdentifierName()
+}
+
+func (p *Parser) parseComputedPropertyName() *Node {
+ // PropertyName [Yield]:
+ // LiteralPropertyName
+ // ComputedPropertyName[?Yield]
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindOpenBracketToken)
+ // We parse any expression (including a comma expression). But the grammar
+ // says that only an assignment expression is allowed, so the grammar checker
+ // will error if it sees a comma expression.
+ expression := p.parseExpressionAllowIn()
+ p.parseExpected(SyntaxKindCloseBracketToken)
+ result := p.factory.NewComputedPropertyName(expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseFunctionBlockOrSemicolon(flags SignatureFlags, diagnosticMessage *diagnostics.Message) *Node {
+ if p.token != SyntaxKindOpenBraceToken {
+ if flags&SignatureFlagsType != 0 {
+ p.parseTypeMemberSemicolon()
+ return nil
+ }
+ if p.canParseSemicolon() {
+ p.parseSemicolon()
+ return nil
+ }
+ }
+ return p.parseFunctionBlock(flags, diagnosticMessage)
+}
+
+func (p *Parser) parseFunctionBlock(flags SignatureFlags, diagnosticMessage *diagnostics.Message) *Node {
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsYieldContext, flags&SignatureFlagsYield != 0)
+ p.setContextFlags(NodeFlagsAwaitContext, flags&SignatureFlagsAwait != 0)
+ // We may be in a [Decorator] context when parsing a function expression or
+ // arrow function. The body of the function is not in [Decorator] context.
+ p.setContextFlags(NodeFlagsDecoratorContext, false)
+ block := p.parseBlock(flags&SignatureFlagsIgnoreMissingOpenBrace != 0, diagnosticMessage)
+ p.contextFlags = saveContextFlags
+ return block
+}
+
+func (p *Parser) isIndexSignature() bool {
+ return p.token == SyntaxKindOpenBracketToken && p.lookAhead(p.nextIsUnambiguouslyIndexSignature)
+}
+
+func (p *Parser) nextIsUnambiguouslyIndexSignature() bool {
+ // The only allowed sequence is:
+ //
+ // [id:
+ //
+ // However, for error recovery, we also check the following cases:
+ //
+ // [...
+ // [id,
+ // [id?,
+ // [id?:
+ // [id?]
+ // [public id
+ // [private id
+ // [protected id
+ // []
+ //
+ p.nextToken()
+ if p.token == SyntaxKindDotDotDotToken || p.token == SyntaxKindCloseBracketToken {
+ return true
+ }
+ if isModifierKind(p.token) {
+ p.nextToken()
+ if p.isIdentifier() {
+ return true
+ }
+ } else if !p.isIdentifier() {
+ return false
+ } else {
+ // Skip the identifier
+ p.nextToken()
+ }
+ // A colon signifies a well formed indexer
+ // A comma should be a badly formed indexer because comma expressions are not allowed
+ // in computed properties.
+ if p.token == SyntaxKindColonToken || p.token == SyntaxKindCommaToken {
+ return true
+ }
+ // Question mark could be an indexer with an optional property,
+ // or it could be a conditional expression in a computed property.
+ if p.token != SyntaxKindQuestionToken {
+ return false
+ }
+ // If any of the following tokens are after the question mark, it cannot
+ // be a conditional expression, so treat it as an indexer.
+ p.nextToken()
+ return p.token == SyntaxKindColonToken || p.token == SyntaxKindCommaToken || p.token == SyntaxKindCloseBracketToken
+}
+
+func (p *Parser) parseIndexSignatureDeclaration(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ parameters := parseBracketedList(p, PCParameters, p.parseParameter, SyntaxKindOpenBracketToken, SyntaxKindCloseBracketToken)
+ typeNode := p.parseTypeAnnotation()
+ p.parseTypeMemberSemicolon()
+ result := p.factory.NewIndexSignatureDeclaration(modifiers, parameters, typeNode)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parsePropertyOrMethodSignature(pos int, hasJSDoc bool, modifiers *Node) *Node {
+ _ = hasJSDoc
+ name := p.parsePropertyName()
+ questionToken := p.parseOptionalToken(SyntaxKindQuestionToken)
+ var result *Node
+ if p.token == SyntaxKindOpenParenToken || p.token == SyntaxKindLessThanToken {
+ // Method signatures don't exist in expression contexts. So they have neither
+ // [Yield] nor [Await]
+ typeParameters := p.parseTypeParameters()
+ parameters := p.parseParameters(SignatureFlagsType)
+ returnType := p.parseReturnType(SyntaxKindColonToken /*isType*/, true)
+ result = p.factory.NewMethodSignatureDeclaration(modifiers, name, questionToken, typeParameters, parameters, returnType)
+ } else {
+ typeNode := p.parseTypeAnnotation()
+ // Although type literal properties cannot not have initializers, we attempt
+ // to parse an initializer so we can report in the checker that an interface
+ // property or type literal property cannot have an initializer.
+ var initializer *Expression
+ if p.token == SyntaxKindEqualsToken {
+ initializer = p.parseInitializer()
+ }
+ result = p.factory.NewPropertySignatureDeclaration(modifiers, name, questionToken, typeNode, initializer)
+ }
+ p.parseTypeMemberSemicolon()
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTypeLiteral() *Node {
+ pos := p.nodePos()
+ result := p.factory.NewTypeLiteralNode(p.parseObjectTypeMembers())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseObjectTypeMembers() []*Node {
+ var members []*Node
+ if p.parseExpected(SyntaxKindOpenBraceToken) {
+ members = parseList(p, PCTypeMembers, p.parseTypeMember)
+ p.parseExpected(SyntaxKindCloseBraceToken)
+ }
+ return members
+}
+
+func (p *Parser) parseTupleType() *Node {
+ pos := p.nodePos()
+ result := p.factory.NewTupleTypeNode(parseBracketedList(p, PCTupleElementTypes, p.parseTupleElementNameOrTupleElementType, SyntaxKindOpenBracketToken, SyntaxKindCloseBracketToken))
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTupleElementNameOrTupleElementType() *Node {
+ if p.lookAhead(p.scanStartOfNamedTupleElement) {
+ pos := p.nodePos()
+ //hasJSDoc := hasPrecedingJSDocComment();
+ dotDotDotToken := p.parseOptionalToken(SyntaxKindDotDotDotToken)
+ name := p.parseIdentifierName()
+ questionToken := p.parseOptionalToken(SyntaxKindQuestionToken)
+ p.parseExpected(SyntaxKindColonToken)
+ typeNode := p.parseTupleElementType()
+ result := p.factory.NewNamedTupleTypeMember(dotDotDotToken, name, questionToken, typeNode)
+ p.finishNode(result, pos)
+ return result
+ }
+ return p.parseTupleElementType()
+}
+
+func (p *Parser) scanStartOfNamedTupleElement() bool {
+ if p.token == SyntaxKindDotDotDotToken {
+ return tokenIsIdentifierOrKeyword(p.nextToken()) && p.nextTokenIsColonOrQuestionColon()
+ }
+ return tokenIsIdentifierOrKeyword(p.token) && p.nextTokenIsColonOrQuestionColon()
+}
+
+func (p *Parser) nextTokenIsColonOrQuestionColon() bool {
+ return p.nextToken() == SyntaxKindColonToken || p.token == SyntaxKindQuestionToken && p.nextToken() == SyntaxKindColonToken
+}
+
+func (p *Parser) parseTupleElementType() *TypeNode {
+ if p.parseOptional(SyntaxKindDotDotDotToken) {
+ pos := p.nodePos()
+ result := p.factory.NewRestTypeNode(p.parseType())
+ p.finishNode(result, pos)
+ return result
+ }
+ typeNode := p.parseType()
+ if typeNode.kind == SyntaxKindJSDocNonNullableType {
+ nullableType := typeNode.data.(*JSDocNonNullableType)
+ if typeNode.loc.pos == nullableType.typeNode.loc.pos {
+ result := p.factory.NewOptionalTypeNode(nullableType.typeNode)
+ result.loc = typeNode.loc
+ result.flags = typeNode.flags
+ return result
+ }
+ }
+ return typeNode
+}
+
+func (p *Parser) parseParenthesizedType() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindOpenParenToken)
+ typeNode := p.parseType()
+ p.parseExpected(SyntaxKindCloseParenToken)
+ result := p.factory.NewParenthesizedTypeNode(typeNode)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseAssertsTypePredicate() *TypeNode {
+ pos := p.nodePos()
+ assertsModifier := p.parseExpectedToken(SyntaxKindAssertsKeyword)
+ var parameterName *Node
+ if p.token == SyntaxKindThisKeyword {
+ parameterName = p.parseThisTypeNode()
+ } else {
+ parameterName = p.parseIdentifier()
+ }
+ var typeNode *TypeNode
+ if p.parseOptional(SyntaxKindIsKeyword) {
+ typeNode = p.parseType()
+ }
+ result := p.factory.NewTypePredicateNode(assertsModifier, parameterName, typeNode)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTemplateType() *Node {
+ pos := p.nodePos()
+ result := p.factory.NewTemplateLiteralTypeNode(p.parseTemplateHead(false /*isTaggedTemplate*/), p.parseTemplateTypeSpans())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTemplateHead(isTaggedTemplate bool) *Node {
+ if !isTaggedTemplate && p.scanner.tokenFlags&TokenFlagsIsInvalid != 0 {
+ p.reScanTemplateToken(false /*isTaggedTemplate*/)
+ }
+ pos := p.nodePos()
+ result := p.factory.NewTemplateHead(p.scanner.tokenValue, p.getTemplateLiteralRawText(2 /*endLength*/), p.scanner.tokenFlags&TokenFlagsTemplateLiteralLikeFlags)
+ p.nextToken()
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) getTemplateLiteralRawText(endLength int) string {
+ tokenText := p.scanner.TokenText()
+ if p.scanner.tokenFlags&TokenFlagsUnterminated != 0 {
+ endLength = 0
+ }
+ return tokenText[1 : len(tokenText)-endLength]
+
+}
+
+func (p *Parser) parseTemplateTypeSpans() []*Node {
+ list := []*Node{}
+ for {
+ span := p.parseTemplateTypeSpan()
+ list = append(list, span)
+ if span.AsTemplateLiteralTypeSpan().literal.kind != SyntaxKindTemplateMiddle {
+ break
+ }
+ }
+ return list
+}
+
+func (p *Parser) parseTemplateTypeSpan() *Node {
+ pos := p.nodePos()
+ result := p.factory.NewTemplateLiteralTypeSpan(p.parseType(), p.parseLiteralOfTemplateSpan(false /*isTaggedTemplate*/))
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseLiteralOfTemplateSpan(isTaggedTemplate bool) *Node {
+ if p.token == SyntaxKindCloseBraceToken {
+ p.reScanTemplateToken(isTaggedTemplate)
+ return p.parseTemplateMiddleOrTail()
+ }
+ p.parseErrorAtCurrentToken(diagnostics.X_0_expected, TokenToString(SyntaxKindCloseBraceToken))
+ result := p.factory.NewTemplateTail("", "", TokenFlagsNone)
+ p.finishNode(result, p.nodePos())
+ return result
+}
+
+func (p *Parser) parseTemplateMiddleOrTail() *Node {
+ pos := p.nodePos()
+ var result *Node
+ if p.token == SyntaxKindTemplateMiddle {
+ result = p.factory.NewTemplateMiddle(p.scanner.tokenValue, p.getTemplateLiteralRawText(2 /*endLength*/), p.scanner.tokenFlags&TokenFlagsTemplateLiteralLikeFlags)
+ } else {
+ result = p.factory.NewTemplateTail(p.scanner.tokenValue, p.getTemplateLiteralRawText(1 /*endLength*/), p.scanner.tokenFlags&TokenFlagsTemplateLiteralLikeFlags)
+ }
+ p.nextToken()
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseFunctionOrConstructorTypeToError(isInUnionType bool, parseConstituentType func() *TypeNode) *TypeNode {
+ // the function type and constructor type shorthand notation
+ // are not allowed directly in unions and intersections, but we'll
+ // try to parse them gracefully and issue a helpful message.
+ if p.isStartOfFunctionTypeOrConstructorType() {
+ typeNode := p.parseFunctionOrConstructorType()
+ var diagnostic *diagnostics.Message
+ if typeNode.kind == SyntaxKindFunctionType {
+ diagnostic = ifElse(isInUnionType,
+ diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_a_union_type,
+ diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_an_intersection_type)
+ } else {
+ diagnostic = ifElse(isInUnionType,
+ diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_a_union_type,
+ diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_an_intersection_type)
+ }
+ p.parseErrorAtRange(typeNode.loc, diagnostic)
+ return typeNode
+ }
+ return parseConstituentType()
+}
+
+func (p *Parser) isStartOfFunctionTypeOrConstructorType() bool {
+ return p.token == SyntaxKindLessThanToken ||
+ p.token == SyntaxKindOpenParenToken && p.lookAhead(p.nextIsUnambiguouslyStartOfFunctionType) ||
+ p.token == SyntaxKindNewKeyword ||
+ p.token == SyntaxKindAbstractKeyword && p.lookAhead(p.nextTokenIsNewKeyword)
+}
+
+func (p *Parser) parseFunctionOrConstructorType() *TypeNode {
+ pos := p.nodePos()
+ // hasJSDoc := p.hasPrecedingJSDocComment()
+ modifiers := p.parseModifiersForConstructorType()
+ isConstructorType := p.parseOptional(SyntaxKindNewKeyword)
+ // Debug.assert(!modifiers || isConstructorType, "Per isStartOfFunctionOrConstructorType, a function type cannot have modifiers.")
+ typeParameters := p.parseTypeParameters()
+ parameters := p.parseParameters(SignatureFlagsType)
+ returnType := p.parseReturnType(SyntaxKindEqualsGreaterThanToken, false /*isType*/)
+ var result *TypeNode
+ if isConstructorType {
+ result = p.factory.NewConstructorTypeNode(modifiers, typeParameters, parameters, returnType)
+ } else {
+ result = p.factory.NewFunctionTypeNode(typeParameters, parameters, returnType)
+ }
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseModifiersForConstructorType() *Node {
+ if p.token == SyntaxKindAbstractKeyword {
+ pos := p.nodePos()
+ modifier := p.factory.NewModifier(p.token)
+ p.nextToken()
+ p.finishNode(modifier, pos)
+ result := p.factory.NewModifierList([]*Node{modifier}, ModifierFlagsAbstract)
+ p.finishNode(result, pos)
+ return result
+ }
+ return nil
+}
+
+func (p *Parser) nextTokenIsNewKeyword() bool {
+ return p.nextToken() == SyntaxKindNewKeyword
+}
+
+func (p *Parser) nextIsUnambiguouslyStartOfFunctionType() bool {
+ p.nextToken()
+ if p.token == SyntaxKindCloseParenToken || p.token == SyntaxKindDotDotDotToken {
+ // ( )
+ // ( ...
+ return true
+ }
+ if p.skipParameterStart() {
+ // We successfully skipped modifiers (if any) and an identifier or binding pattern,
+ // now see if we have something that indicates a parameter declaration
+ if p.token == SyntaxKindColonToken || p.token == SyntaxKindCommaToken || p.token == SyntaxKindQuestionToken || p.token == SyntaxKindEqualsToken {
+ // ( xxx :
+ // ( xxx ,
+ // ( xxx ?
+ // ( xxx =
+ return true
+ }
+ if p.token == SyntaxKindCloseParenToken && p.nextToken() == SyntaxKindEqualsGreaterThanToken {
+ // ( xxx ) =>
+ return true
+ }
+ }
+ return false
+}
+
+func (p *Parser) skipParameterStart() bool {
+ if isModifierKind(p.token) {
+ // Skip modifiers
+ p.parseModifiers()
+ }
+ p.parseOptional(SyntaxKindDotDotDotToken)
+ if p.isIdentifier() || p.token == SyntaxKindThisKeyword {
+ p.nextToken()
+ return true
+ }
+ if p.token == SyntaxKindOpenBracketToken || p.token == SyntaxKindOpenBraceToken {
+ // Return true if we can parse an array or object binding pattern with no errors
+ previousErrorCount := len(p.diagnostics)
+ p.parseIdentifierOrPattern()
+ return previousErrorCount == len(p.diagnostics)
+ }
+ return false
+}
+
+func (p *Parser) parseModifiers() *Node {
+ return p.parseModifiersWithOptions(false, false, false)
+}
+
+func (p *Parser) parseModifiersWithOptions(allowDecorators bool, permitConstAsModifier bool, stopOnStartOfClassStaticBlock bool) *Node {
+ pos := p.nodePos()
+ list := []*Node{}
+ preModifierFlags := ModifierFlagsNone
+ decoratorFlag := ModifierFlagsNone
+ postModifierFlags := ModifierFlagsNone
+ // Decorators should be contiguous in a list of modifiers but can potentially appear in two places (i.e., `[...leadingDecorators, ...leadingModifiers, ...trailingDecorators, ...trailingModifiers]`).
+ // The leading modifiers *should* only contain `export` and `default` when trailingDecorators are present, but we'll handle errors for any other leading modifiers in the checker.
+ // It is illegal to have both leadingDecorators and trailingDecorators, but we will report that as a grammar check in the checker.
+ // parse leading decorators
+ for {
+ if allowDecorators && p.token == SyntaxKindAtToken && postModifierFlags == ModifierFlagsNone {
+ decorator := p.parseDecorator()
+ list = append(list, decorator)
+ decoratorFlag |= ModifierFlagsDecorator
+ } else {
+ modifier := p.tryParseModifier((preModifierFlags|postModifierFlags)&ModifierFlagsStatic != 0, permitConstAsModifier, stopOnStartOfClassStaticBlock)
+ if modifier == nil {
+ break
+ }
+ list = append(list, modifier)
+ flag := modifierToFlag(modifier.kind)
+ if decoratorFlag == ModifierFlagsNone {
+ preModifierFlags |= flag
+ } else {
+ postModifierFlags |= flag
+ }
+ }
+ }
+ if len(list) > 0 {
+ result := p.factory.NewModifierList(list, preModifierFlags|decoratorFlag|postModifierFlags)
+ p.finishNode(result, pos)
+ return result
+ }
+ return nil
+}
+
+func (p *Parser) parseDecorator() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindAtToken)
+ expression := doInContext(p, NodeFlagsDecoratorContext, true, p.parseDecoratorExpression)
+ result := p.factory.NewDecorator(expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseDecoratorExpression() *Expression {
+ if p.inAwaitContext() && p.token == SyntaxKindAwaitKeyword {
+ // `@await` is is disallowed in an [Await] context, but can cause parsing to go off the rails
+ // This simply parses the missing identifier and moves on.
+ pos := p.nodePos()
+ awaitExpression := p.parseIdentifierWithDiagnostic(diagnostics.Expression_expected, nil)
+ p.nextToken()
+ memberExpression := p.parseMemberExpressionRest(pos, awaitExpression /*allowOptionalChain*/, true)
+ return p.parseCallExpressionRest(pos, memberExpression)
+ }
+ return p.parseLeftHandSideExpressionOrHigher()
+}
+
+func (p *Parser) tryParseModifier(hasSeenStaticModifier bool, permitConstAsModifier bool, stopOnStartOfClassStaticBlock bool) *Node {
+ pos := p.nodePos()
+ kind := p.token
+ if p.token == SyntaxKindConstKeyword && permitConstAsModifier {
+ // We need to ensure that any subsequent modifiers appear on the same line
+ // so that when 'const' is a standalone declaration, we don't issue an error.
+ if !p.lookAhead(p.nextTokenIsOnSameLineAndCanFollowModifier) {
+ return nil
+ } else {
+ p.nextToken()
+ }
+ } else if stopOnStartOfClassStaticBlock && p.token == SyntaxKindStaticKeyword && p.lookAhead(p.nextTokenIsOpenBrace) {
+ return nil
+ } else if hasSeenStaticModifier && p.token == SyntaxKindStaticKeyword {
+ return nil
+ } else {
+ if !p.parseAnyContextualModifier() {
+ return nil
+ }
+ }
+ result := p.factory.NewModifier(kind)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseContextualModifier(t SyntaxKind) bool {
+ state := p.mark()
+ if p.token == t && p.nextTokenCanFollowModifier() {
+ return true
+ }
+ p.rewind(state)
+ return false
+}
+
+func (p *Parser) parseAnyContextualModifier() bool {
+ state := p.mark()
+ if isModifierKind(p.token) && p.nextTokenCanFollowModifier() {
+ return true
+ }
+ p.rewind(state)
+ return false
+}
+
+func (p *Parser) nextTokenCanFollowModifier() bool {
+ switch p.token {
+ case SyntaxKindConstKeyword:
+ // 'const' is only a modifier if followed by 'enum'.
+ return p.nextToken() == SyntaxKindEnumKeyword
+ case SyntaxKindExportKeyword:
+ p.nextToken()
+ if p.token == SyntaxKindDefaultKeyword {
+ return p.lookAhead(p.nextTokenCanFollowDefaultKeyword)
+ }
+ if p.token == SyntaxKindTypeKeyword {
+ return p.lookAhead(p.nextTokenCanFollowExportModifier)
+ }
+ return p.canFollowExportModifier()
+ case SyntaxKindDefaultKeyword:
+ return p.nextTokenCanFollowDefaultKeyword()
+ case SyntaxKindStaticKeyword, SyntaxKindGetKeyword, SyntaxKindSetKeyword:
+ p.nextToken()
+ return p.canFollowModifier()
+ default:
+ return p.nextTokenIsOnSameLineAndCanFollowModifier()
+ }
+}
+
+func (p *Parser) nextTokenCanFollowDefaultKeyword() bool {
+ switch p.nextToken() {
+ case SyntaxKindClassKeyword, SyntaxKindFunctionKeyword, SyntaxKindInterfaceKeyword, SyntaxKindAtToken:
+ return true
+ case SyntaxKindAbstractKeyword:
+ return p.lookAhead(p.nextTokenIsClassKeywordOnSameLine)
+ case SyntaxKindAsyncKeyword:
+ return p.lookAhead(p.nextTokenIsFunctionKeywordOnSameLine)
+ }
+ return false
+}
+
+func (p *Parser) nextTokenIsIdentifierOrKeyword() bool {
+ return tokenIsIdentifierOrKeyword(p.nextToken())
+}
+
+func (p *Parser) nextTokenIsIdentifierOrKeywordOrGreaterThan() bool {
+ return tokenIsIdentifierOrKeywordOrGreaterThan(p.nextToken())
+}
+
+func (p *Parser) nextTokenIsIdentifierOrKeywordOnSameLine() bool {
+ return p.nextTokenIsIdentifierOrKeyword() && !p.hasPrecedingLineBreak()
+}
+
+func (p *Parser) nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() bool {
+ return (p.nextTokenIsIdentifierOrKeyword() || p.token == SyntaxKindNumericLiteral || p.token == SyntaxKindBigintLiteral || p.token == SyntaxKindStringLiteral) && !p.hasPrecedingLineBreak()
+}
+
+func (p *Parser) nextTokenIsClassKeywordOnSameLine() bool {
+ return p.nextToken() == SyntaxKindClassKeyword && !p.hasPrecedingLineBreak()
+}
+
+func (p *Parser) nextTokenIsFunctionKeywordOnSameLine() bool {
+ return p.nextToken() == SyntaxKindFunctionKeyword && !p.hasPrecedingLineBreak()
+}
+
+func (p *Parser) nextTokenCanFollowExportModifier() bool {
+ p.nextToken()
+ return p.canFollowExportModifier()
+}
+
+func (p *Parser) canFollowExportModifier() bool {
+ return p.token == SyntaxKindAtToken || p.token != SyntaxKindAsteriskToken && p.token != SyntaxKindAsKeyword && p.token != SyntaxKindOpenBraceToken && p.canFollowModifier()
+}
+
+func (p *Parser) canFollowModifier() bool {
+ return p.token == SyntaxKindOpenBracketToken || p.token == SyntaxKindOpenBraceToken || p.token == SyntaxKindAsteriskToken || p.token == SyntaxKindDotDotDotToken || p.isLiteralPropertyName()
+}
+
+func (p *Parser) nextTokenIsOnSameLineAndCanFollowModifier() bool {
+ p.nextToken()
+ if p.hasPrecedingLineBreak() {
+ return false
+ }
+ return p.canFollowModifier()
+}
+
+func (p *Parser) nextTokenIsOpenBrace() bool {
+ return p.nextToken() == SyntaxKindOpenBraceToken
+}
+
+func (p *Parser) parseExpression() *Expression {
+ // Expression[in]:
+ // AssignmentExpression[in]
+ // Expression[in] , AssignmentExpression[in]
+
+ // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator
+ saveContextFlags := p.contextFlags
+ p.contextFlags &= ^NodeFlagsDecoratorContext
+ pos := p.nodePos()
+ expr := p.parseAssignmentExpressionOrHigher()
+ for {
+ operatorToken := p.parseOptionalToken(SyntaxKindCommaToken)
+ if operatorToken == nil {
+ break
+ }
+ expr = p.makeBinaryExpression(expr, operatorToken, p.parseAssignmentExpressionOrHigher(), pos)
+ }
+ p.contextFlags = saveContextFlags
+ return expr
+}
+
+func (p *Parser) parseExpressionAllowIn() *Expression {
+ return doInContext(p, NodeFlagsDisallowInContext, false, p.parseExpression)
+}
+
+func (p *Parser) parseAssignmentExpressionOrHigher() *Expression {
+ return p.parseAssignmentExpressionOrHigherWorker(true /*allowReturnTypeInArrowFunction*/)
+}
+
+func (p *Parser) parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowFunction bool) *Expression {
+ // AssignmentExpression[in,yield]:
+ // 1) ConditionalExpression[?in,?yield]
+ // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield]
+ // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield]
+ // 4) ArrowFunctionExpression[?in,?yield]
+ // 5) AsyncArrowFunctionExpression[in,yield,await]
+ // 6) [+Yield] YieldExpression[?In]
+ //
+ // Note: for ease of implementation we treat productions '2' and '3' as the same thing.
+ // (i.e. they're both BinaryExpressions with an assignment operator in it).
+ // First, do the simple check if we have a YieldExpression (production '6').
+ if p.isYieldExpression() {
+ return p.parseYieldExpression()
+ }
+ // Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized
+ // parameter list or is an async arrow function.
+ // AsyncArrowFunctionExpression:
+ // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
+ // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
+ // Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression".
+ // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression".
+ //
+ // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is
+ // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done
+ // with AssignmentExpression if we see one.
+ arrowExpression := p.tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction)
+ if arrowExpression != nil {
+ return arrowExpression
+ }
+ arrowExpression = p.tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction)
+ if arrowExpression != nil {
+ return arrowExpression
+ }
+ // arrowExpression2 := p.tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction)
+ // if arrowExpression2 != nil {
+ // return arrowExpression2
+ // }
+ // Now try to see if we're in production '1', '2' or '3'. A conditional expression can
+ // start with a LogicalOrExpression, while the assignment productions can only start with
+ // LeftHandSideExpressions.
+ //
+ // So, first, we try to just parse out a BinaryExpression. If we get something that is a
+ // LeftHandSide or higher, then we can try to parse out the assignment expression part.
+ // Otherwise, we try to parse out the conditional expression bit. We want to allow any
+ // binary expression here, so we pass in the 'lowest' precedence here so that it matches
+ // and consumes anything.
+ pos := p.nodePos()
+ hasJSDoc := p.hasPrecedingJSDocComment()
+ expr := p.parseBinaryExpressionOrHigher(OperatorPrecedenceLowest)
+ // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized
+ // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single
+ // identifier and the current token is an arrow.
+ if expr.kind == SyntaxKindIdentifier && p.token == SyntaxKindEqualsGreaterThanToken {
+ return p.parseSimpleArrowFunctionExpression(pos, expr, allowReturnTypeInArrowFunction, hasJSDoc, nil /*asyncModifier*/)
+ }
+ // Now see if we might be in cases '2' or '3'.
+ // If the expression was a LHS expression, and we have an assignment operator, then
+ // we're in '2' or '3'. Consume the assignment and return.
+ //
+ // Note: we call reScanGreaterToken so that we get an appropriately merged token
+ // for cases like `> > =` becoming `>>=`
+ if isLeftHandSideExpressionKind(expr.kind) && isAssignmentOperator(p.reScanGreaterThanToken()) {
+ return p.makeBinaryExpression(expr, p.parseTokenNode(), p.parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowFunction), pos)
+ }
+ // It wasn't an assignment or a lambda. This is a conditional expression:
+ return p.parseConditionalExpressionRest(expr, pos, allowReturnTypeInArrowFunction)
+}
+
+func (p *Parser) isYieldExpression() bool {
+ if p.token == SyntaxKindYieldKeyword {
+ // If we have a 'yield' keyword, and this is a context where yield expressions are
+ // allowed, then definitely parse out a yield expression.
+ if p.inYieldContext() {
+ return true
+ }
+
+ // We're in a context where 'yield expr' is not allowed. However, if we can
+ // definitely tell that the user was trying to parse a 'yield expr' and not
+ // just a normal expr that start with a 'yield' identifier, then parse out
+ // a 'yield expr'. We can then report an error later that they are only
+ // allowed in generator expressions.
+ //
+ // for example, if we see 'yield(foo)', then we'll have to treat that as an
+ // invocation expression of something called 'yield'. However, if we have
+ // 'yield foo' then that is not legal as a normal expression, so we can
+ // definitely recognize this as a yield expression.
+ //
+ // for now we just check if the next token is an identifier. More heuristics
+ // can be added here later as necessary. We just need to make sure that we
+ // don't accidentally consume something legal.
+ return p.lookAhead(p.nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine)
+ }
+ return false
+}
+
+func (p *Parser) parseYieldExpression() *Node {
+ pos := p.nodePos()
+ // YieldExpression[In] :
+ // yield
+ // yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield]
+ // yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield]
+ p.nextToken()
+ var result *Node
+ if !p.hasPrecedingLineBreak() && (p.token == SyntaxKindAsteriskToken || p.isStartOfExpression()) {
+ result = p.factory.NewYieldExpression(p.parseOptionalToken(SyntaxKindAsteriskToken), p.parseAssignmentExpressionOrHigher())
+ } else {
+ // if the next token is not on the same line as yield. or we don't have an '*' or
+ // the start of an expression, then this is just a simple "yield" expression.
+ result = p.factory.NewYieldExpression(nil /*asteriskToken*/, nil /*expression*/)
+ }
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) isParenthesizedArrowFunctionExpression() Tristate {
+ if p.token == SyntaxKindOpenParenToken || p.token == SyntaxKindLessThanToken || p.token == SyntaxKindAsyncKeyword {
+ state := p.mark()
+ result := p.nextIsParenthesizedArrowFunctionExpression()
+ p.rewind(state)
+ return result
+ }
+ if p.token == SyntaxKindEqualsGreaterThanToken {
+ // ERROR RECOVERY TWEAK:
+ // If we see a standalone => try to parse it as an arrow function expression as that's
+ // likely what the user intended to write.
+ return TSTrue
+ }
+ // Definitely not a parenthesized arrow function.
+ return TSFalse
+}
+
+func (p *Parser) nextIsParenthesizedArrowFunctionExpression() Tristate {
+ if p.token == SyntaxKindAsyncKeyword {
+ p.nextToken()
+ if p.hasPrecedingLineBreak() {
+ return TSFalse
+ }
+ if p.token != SyntaxKindOpenParenToken && p.token != SyntaxKindLessThanToken {
+ return TSFalse
+ }
+ }
+ first := p.token
+ second := p.nextToken()
+ if first == SyntaxKindOpenParenToken {
+ if second == SyntaxKindCloseParenToken {
+ // Simple cases: "() =>", "(): ", and "() {".
+ // This is an arrow function with no parameters.
+ // The last one is not actually an arrow function,
+ // but this is probably what the user intended.
+ third := p.nextToken()
+ switch third {
+ case SyntaxKindEqualsGreaterThanToken, SyntaxKindColonToken, SyntaxKindOpenBraceToken:
+ return TSTrue
+ }
+ return TSFalse
+ }
+ // If encounter "([" or "({", this could be the start of a binding pattern.
+ // Examples:
+ // ([ x ]) => { }
+ // ({ x }) => { }
+ // ([ x ])
+ // ({ x })
+ if second == SyntaxKindOpenBracketToken || second == SyntaxKindOpenBraceToken {
+ return TSUnknown
+ }
+ // Simple case: "(..."
+ // This is an arrow function with a rest parameter.
+ if second == SyntaxKindDotDotDotToken {
+ return TSTrue
+ }
+ // Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This
+ // isn't actually allowed, but we want to treat it as a lambda so we can provide
+ // a good error message.
+ if isModifierKind(second) && second != SyntaxKindAsyncKeyword && p.lookAhead(p.nextTokenIsIdentifier) {
+ if p.nextToken() == SyntaxKindAsKeyword {
+ // https://github.com/microsoft/TypeScript/issues/44466
+ return TSFalse
+ }
+ return TSTrue
+ }
+ // If we had "(" followed by something that's not an identifier,
+ // then this definitely doesn't look like a lambda. "this" is not
+ // valid, but we want to parse it and then give a semantic error.
+ if !p.isIdentifier() && second != SyntaxKindThisKeyword {
+ return TSFalse
+ }
+ switch p.nextToken() {
+ case SyntaxKindColonToken:
+ // If we have something like "(a:", then we must have a
+ // type-annotated parameter in an arrow function expression.
+ return TSTrue
+ case SyntaxKindQuestionToken:
+ p.nextToken()
+ // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda.
+ if p.token == SyntaxKindColonToken || p.token == SyntaxKindCommaToken || p.token == SyntaxKindEqualsToken || p.token == SyntaxKindCloseParenToken {
+ return TSTrue
+ }
+ // Otherwise it is definitely not a lambda.
+ return TSFalse
+ case SyntaxKindCommaToken, SyntaxKindEqualsToken, SyntaxKindCloseParenToken:
+ // If we have "(a," or "(a=" or "(a)" this *could* be an arrow function
+ return TSUnknown
+ }
+ // It is definitely not an arrow function
+ return TSFalse
+ } else {
+ // !!! Debug.assert(first == SyntaxKindLessThanToken)
+ // If we have "<" not followed by an identifier,
+ // then this definitely is not an arrow function.
+ if !p.isIdentifier() && p.token != SyntaxKindConstKeyword {
+ return TSFalse
+ }
+ // JSX overrides
+ if p.languageVariant == LanguageVariantJSX {
+ isArrowFunctionInJsx := p.lookAhead(func() bool {
+ p.parseOptional(SyntaxKindConstKeyword)
+ third := p.nextToken()
+ if third == SyntaxKindExtendsKeyword {
+ fourth := p.nextToken()
+ switch fourth {
+ case SyntaxKindEqualsToken, SyntaxKindGreaterThanToken, SyntaxKindSlashToken:
+ return false
+ }
+ return true
+ } else if third == SyntaxKindCommaToken || third == SyntaxKindEqualsToken {
+ return true
+ }
+ return false
+ })
+ if isArrowFunctionInJsx {
+ return TSTrue
+ }
+ return TSFalse
+ }
+ // This *could* be a parenthesized arrow function.
+ return TSUnknown
+ }
+}
+
+func (p *Parser) tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction bool) *Node {
+ tristate := p.isParenthesizedArrowFunctionExpression()
+ if tristate == TSFalse {
+ // It's definitely not a parenthesized arrow function expression.
+ return nil
+ }
+ // If we definitely have an arrow function, then we can just parse one, not requiring a
+ // following => or { token. Otherwise, we *might* have an arrow function. Try to parse
+ // it out, but don't allow any ambiguity, and return 'undefined' if this could be an
+ // expression instead.
+ if tristate == TSTrue {
+ return p.parseParenthesizedArrowFunctionExpression(true /*allowAmbiguity*/, true /*allowReturnTypeInArrowFunction*/)
+ }
+ state := p.mark()
+ result := p.parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction)
+ if result == nil {
+ p.rewind(state)
+ }
+ return result
+}
+
+func (p *Parser) parseParenthesizedArrowFunctionExpression(allowAmbiguity bool, allowReturnTypeInArrowFunction bool) *Node {
+ pos := p.nodePos()
+ // hasJSDoc := p.hasPrecedingJSDocComment()
+ modifiers := p.parseModifiersForArrowFunction()
+ isAsync := hasAsyncModifier(modifiers)
+ signatureFlags := ifElse(isAsync, SignatureFlagsAwait, SignatureFlagsNone)
+ // Arrow functions are never generators.
+ //
+ // If we're speculatively parsing a signature for a parenthesized arrow function, then
+ // we have to have a complete parameter list. Otherwise we might see something like
+ // a => (b => c)
+ // And think that "(b =>" was actually a parenthesized arrow function with a missing
+ // close paren.
+ typeParameters := p.parseTypeParameters()
+ var parameters []*Node
+ if !p.parseExpected(SyntaxKindOpenParenToken) {
+ if !allowAmbiguity {
+ return nil
+ }
+ } else {
+ if !allowAmbiguity {
+ maybeParameters := p.parseParametersWorker(signatureFlags, allowAmbiguity)
+ if maybeParameters == nil {
+ return nil
+ }
+ parameters = maybeParameters
+ } else {
+ parameters = p.parseParametersWorker(signatureFlags, allowAmbiguity)
+ }
+ if !p.parseExpected(SyntaxKindCloseParenToken) && !allowAmbiguity {
+ return nil
+ }
+ }
+ hasReturnColon := p.token == SyntaxKindColonToken
+ returnType := p.parseReturnType(SyntaxKindColonToken /*isType*/, false)
+ if returnType != nil && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(returnType) {
+ return nil
+ }
+ // Parsing a signature isn't enough.
+ // Parenthesized arrow signatures often look like other valid expressions.
+ // For instance:
+ // - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value.
+ // - "(x,y)" is a comma expression parsed as a signature with two parameters.
+ // - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation.
+ // - "a ? (b): function() {}" will too, since function() is a valid JSDoc function type.
+ // - "a ? (b): (function() {})" as well, but inside of a parenthesized type with an arbitrary amount of nesting.
+ //
+ // So we need just a bit of lookahead to ensure that it can only be a signature.
+ unwrappedType := returnType
+ for unwrappedType != nil && unwrappedType.kind == SyntaxKindParenthesizedType {
+ unwrappedType = unwrappedType.AsParenthesizedTypeNode().typeNode // Skip parens if need be
+ }
+ hasJSDocFunctionType := unwrappedType != nil && unwrappedType.kind == SyntaxKindJSDocFunctionType
+ if !allowAmbiguity && p.token != SyntaxKindEqualsGreaterThanToken && (hasJSDocFunctionType || p.token != SyntaxKindOpenBraceToken) {
+ // Returning undefined here will cause our caller to rewind to where we started from.
+ return nil
+ }
+ // If we have an arrow, then try to parse the body. Even if not, try to parse if we
+ // have an opening brace, just in case we're in an error state.
+ lastToken := p.token
+ equalsGreaterThanToken := p.parseExpectedToken(SyntaxKindEqualsGreaterThanToken)
+ var body *Node
+ if lastToken == SyntaxKindEqualsGreaterThanToken || lastToken == SyntaxKindOpenBraceToken {
+ body = p.parseArrowFunctionExpressionBody(isAsync, allowReturnTypeInArrowFunction)
+ } else {
+ body = p.parseIdentifier()
+ }
+ // Given:
+ // x ? y => ({ y }) : z => ({ z })
+ // We try to parse the body of the first arrow function by looking at:
+ // ({ y }) : z => ({ z })
+ // This is a valid arrow function with "z" as the return type.
+ //
+ // But, if we're in the true side of a conditional expression, this colon
+ // terminates the expression, so we cannot allow a return type if we aren't
+ // certain whether or not the preceding text was parsed as a parameter list.
+ //
+ // For example,
+ // a() ? (b: number, c?: string): void => d() : e
+ // is determined by isParenthesizedArrowFunctionExpression to unambiguously
+ // be an arrow expression, so we allow a return type.
+ if !allowReturnTypeInArrowFunction && hasReturnColon {
+ // However, if the arrow function we were able to parse is followed by another colon
+ // as in:
+ // a ? (x): string => x : null
+ // Then allow the arrow function, and treat the second colon as terminating
+ // the conditional expression. It's okay to do this because this code would
+ // be a syntax error in JavaScript (as the second colon shouldn't be there).
+ if p.token != SyntaxKindColonToken {
+ return nil
+ }
+ }
+ result := p.factory.NewArrowFunction(modifiers, typeParameters, parameters, returnType, equalsGreaterThanToken, body)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseModifiersForArrowFunction() *Node {
+ if p.token == SyntaxKindAsyncKeyword {
+ pos := p.nodePos()
+ p.nextToken()
+ modifier := p.factory.NewModifier(SyntaxKindAsyncKeyword)
+ p.finishNode(modifier, pos)
+ result := p.factory.NewModifierList([]*Node{modifier}, ModifierFlagsAsync)
+ p.finishNode(modifier, pos)
+ return result
+ }
+ return nil
+}
+
+// If true, we should abort parsing an error function.
+func typeHasArrowFunctionBlockingParseError(node *TypeNode) bool {
+ switch node.kind {
+ case SyntaxKindTypeReference:
+ return nodeIsMissing(node.AsTypeReference().typeName)
+ case SyntaxKindFunctionType, SyntaxKindConstructorType:
+ return node.FunctionLikeData().parameters == nil || typeHasArrowFunctionBlockingParseError(node.FunctionLikeData().returnType)
+ case SyntaxKindParenthesizedType:
+ return typeHasArrowFunctionBlockingParseError(node.AsParenthesizedTypeNode().typeNode)
+ }
+ return false
+}
+
+func (p *Parser) parseArrowFunctionExpressionBody(isAsync bool, allowReturnTypeInArrowFunction bool) *Node {
+ if p.token == SyntaxKindOpenBraceToken {
+ return p.parseFunctionBlock(ifElse(isAsync, SignatureFlagsAwait, SignatureFlagsNone), nil /*diagnosticMessage*/)
+ }
+ if p.token != SyntaxKindSemicolonToken && p.token != SyntaxKindFunctionKeyword && p.token != SyntaxKindClassKeyword && p.isStartOfStatement() && !p.isStartOfExpressionStatement() {
+ // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations)
+ //
+ // Here we try to recover from a potential error situation in the case where the
+ // user meant to supply a block. For example, if the user wrote:
+ //
+ // a =>
+ // let v = 0;
+ // }
+ //
+ // they may be missing an open brace. Check to see if that's the case so we can
+ // try to recover better. If we don't do this, then the next close curly we see may end
+ // up preemptively closing the containing construct.
+ //
+ // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error.
+ return p.parseFunctionBlock(SignatureFlagsIgnoreMissingOpenBrace|ifElse(isAsync, SignatureFlagsAwait, SignatureFlagsNone), nil /*diagnosticMessage*/)
+ }
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsAwaitContext, isAsync)
+ node := p.parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowFunction)
+ p.contextFlags = saveContextFlags
+ return node
+}
+
+func (p *Parser) isStartOfExpressionStatement() bool {
+ // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement.
+ return p.token != SyntaxKindOpenBraceToken && p.token != SyntaxKindFunctionKeyword && p.token != SyntaxKindClassKeyword && p.token != SyntaxKindAtToken && p.isStartOfExpression()
+}
+
+func (p *Parser) parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction bool) *Node {
+ tokenPos := p.scanner.TokenStart()
+ if p.notParenthesizedArrow[tokenPos] {
+ return nil
+ }
+ result := p.parseParenthesizedArrowFunctionExpression(false /*allowAmbiguity*/, allowReturnTypeInArrowFunction)
+ if result == nil {
+ if p.notParenthesizedArrow == nil {
+ p.notParenthesizedArrow = make(map[int]bool)
+ }
+ p.notParenthesizedArrow[tokenPos] = true
+ }
+ return result
+}
+
+func (p *Parser) tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction bool) *Node {
+ // We do a check here so that we won't be doing unnecessarily call to "lookAhead"
+ if p.token == SyntaxKindAsyncKeyword && p.lookAhead(p.nextIsUnParenthesizedAsyncArrowFunction) {
+ pos := p.nodePos()
+ hasJSDoc := p.hasPrecedingJSDocComment()
+ asyncModifier := p.parseModifiersForArrowFunction()
+ expr := p.parseBinaryExpressionOrHigher(OperatorPrecedenceLowest)
+ return p.parseSimpleArrowFunctionExpression(pos, expr, allowReturnTypeInArrowFunction, hasJSDoc, asyncModifier)
+ }
+ return nil
+}
+
+func (p *Parser) nextIsUnParenthesizedAsyncArrowFunction() bool {
+ // AsyncArrowFunctionExpression:
+ // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
+ // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
+ if p.token == SyntaxKindAsyncKeyword {
+ p.nextToken()
+ // If the "async" is followed by "=>" token then it is not a beginning of an async arrow-function
+ // but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher"
+ if p.hasPrecedingLineBreak() || p.token == SyntaxKindEqualsGreaterThanToken {
+ return false
+ }
+ // Check for un-parenthesized AsyncArrowFunction
+ expr := p.parseBinaryExpressionOrHigher(OperatorPrecedenceLowest)
+ if !p.hasPrecedingLineBreak() && expr.kind == SyntaxKindIdentifier && p.token == SyntaxKindEqualsGreaterThanToken {
+ return true
+ }
+ }
+ return false
+}
+
+func (p *Parser) parseSimpleArrowFunctionExpression(pos int, identifier *Node, allowReturnTypeInArrowFunction bool, hasJSDoc bool, asyncModifier *Node) *Node {
+ //Debug.assert(token() == SyntaxKindEqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>");
+ parameter := p.factory.NewParameterDeclaration(nil /*modifiers*/, nil /*dotDotDotToken*/, identifier, nil /*questionToken*/, nil /*typeNode*/, nil /*initializer*/)
+ p.finishNode(parameter, identifier.Pos())
+ parameters := []*Node{parameter}
+ equalsGreaterThanToken := p.parseExpectedToken(SyntaxKindEqualsGreaterThanToken)
+ body := p.parseArrowFunctionExpressionBody(asyncModifier != nil /*isAsync*/, allowReturnTypeInArrowFunction)
+ result := p.factory.NewArrowFunction(asyncModifier, nil /*typeParameters*/, parameters, nil /*returnType*/, equalsGreaterThanToken, body)
+ p.finishNode(result, pos)
+ _ = hasJSDoc
+ return result
+}
+
+func (p *Parser) parseConditionalExpressionRest(leftOperand *Expression, pos int, allowReturnTypeInArrowFunction bool) *Expression {
+ // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher.
+ questionToken := p.parseOptionalToken(SyntaxKindQuestionToken)
+ if questionToken == nil {
+ return leftOperand
+ }
+ // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and
+ // we do not that for the 'whenFalse' part.
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsDisallowInContext, false)
+ trueExpression := p.parseAssignmentExpressionOrHigherWorker(false /*allowReturnTypeInArrowFunction*/)
+ p.contextFlags = saveContextFlags
+ colonToken := p.parseExpectedToken(SyntaxKindColonToken)
+ var falseExpression *Expression
+ if colonToken != nil {
+ falseExpression = p.parseAssignmentExpressionOrHigherWorker(allowReturnTypeInArrowFunction)
+ } else {
+ p.parseErrorAtCurrentToken(diagnostics.X_0_expected, TokenToString(SyntaxKindColonToken))
+ falseExpression = p.createMissingIdentifier()
+ }
+ result := p.factory.NewConditionalExpression(leftOperand, questionToken, trueExpression, colonToken, falseExpression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseBinaryExpressionOrHigher(precedence OperatorPrecedence) *Expression {
+ pos := p.nodePos()
+ leftOperand := p.parseUnaryExpressionOrHigher()
+ return p.parseBinaryExpressionRest(precedence, leftOperand, pos)
+}
+
+func (p *Parser) parseBinaryExpressionRest(precedence OperatorPrecedence, leftOperand *Expression, pos int) *Expression {
+ for {
+ // We either have a binary operator here, or we're finished. We call
+ // reScanGreaterToken so that we merge token sequences like > and = into >=
+ p.reScanGreaterThanToken()
+ newPrecedence := getBinaryOperatorPrecedence(p.token)
+ // Check the precedence to see if we should "take" this operator
+ // - For left associative operator (all operator but **), consume the operator,
+ // recursively call the function below, and parse binaryExpression as a rightOperand
+ // of the caller if the new precedence of the operator is greater then or equal to the current precedence.
+ // For example:
+ // a - b - c;
+ // ^token; leftOperand = b. Return b to the caller as a rightOperand
+ // a * b - c
+ // ^token; leftOperand = b. Return b to the caller as a rightOperand
+ // a - b * c;
+ // ^token; leftOperand = b. Return b * c to the caller as a rightOperand
+ // - For right associative operator (**), consume the operator, recursively call the function
+ // and parse binaryExpression as a rightOperand of the caller if the new precedence of
+ // the operator is strictly grater than the current precedence
+ // For example:
+ // a ** b ** c;
+ // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand
+ // a - b ** c;
+ // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand
+ // a ** b - c
+ // ^token; leftOperand = b. Return b to the caller as a rightOperand
+ var consumeCurrentOperator bool
+ if p.token == SyntaxKindAsteriskAsteriskToken {
+ consumeCurrentOperator = newPrecedence >= precedence
+ } else {
+ consumeCurrentOperator = newPrecedence > precedence
+ }
+ if !consumeCurrentOperator {
+ break
+ }
+ if p.token == SyntaxKindInKeyword && p.inDisallowInContext() {
+ break
+ }
+ if p.token == SyntaxKindAsKeyword || p.token == SyntaxKindSatisfiesKeyword {
+ // Make sure we *do* perform ASI for constructs like this:
+ // var x = foo
+ // as (Bar)
+ // This should be parsed as an initialized variable, followed
+ // by a function call to 'as' with the argument 'Bar'
+ if p.hasPrecedingLineBreak() {
+ break
+ } else {
+ keywordKind := p.token
+ p.nextToken()
+ if keywordKind == SyntaxKindSatisfiesKeyword {
+ leftOperand = p.makeSatisfiesExpression(leftOperand, p.parseType())
+ } else {
+ leftOperand = p.makeAsExpression(leftOperand, p.parseType())
+ }
+ }
+ } else {
+ leftOperand = p.makeBinaryExpression(leftOperand, p.parseTokenNode(), p.parseBinaryExpressionOrHigher(newPrecedence), pos)
+ }
+ }
+ return leftOperand
+}
+
+func (p *Parser) makeSatisfiesExpression(expression *Expression, typeNode *TypeNode) *Node {
+ result := p.factory.NewSatisfiesExpression(expression, typeNode)
+ p.finishNode(result, expression.Pos())
+ return result
+}
+
+func (p *Parser) makeAsExpression(left *Expression, right *TypeNode) *Node {
+ result := p.factory.NewAsExpression(left, right)
+ p.finishNode(result, left.Pos())
+ return result
+}
+
+func (p *Parser) makeBinaryExpression(left *Expression, operatorToken *Node, right *Expression, pos int) *Node {
+ result := p.factory.NewBinaryExpression(left, operatorToken, right)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseUnaryExpressionOrHigher() *Expression {
+ // ES7 UpdateExpression:
+ // 1) LeftHandSideExpression[?Yield]
+ // 2) LeftHandSideExpression[?Yield][no LineTerminator here]++
+ // 3) LeftHandSideExpression[?Yield][no LineTerminator here]--
+ // 4) ++UnaryExpression[?Yield]
+ // 5) --UnaryExpression[?Yield]
+ if p.isUpdateExpression() {
+ pos := p.nodePos()
+ updateExpression := p.parseUpdateExpression()
+ if p.token == SyntaxKindAsteriskAsteriskToken {
+ return p.parseBinaryExpressionRest(getBinaryOperatorPrecedence(p.token), updateExpression, pos)
+ }
+ return updateExpression
+ }
+ // ES7 UnaryExpression:
+ // 1) UpdateExpression[?yield]
+ // 2) delete UpdateExpression[?yield]
+ // 3) void UpdateExpression[?yield]
+ // 4) typeof UpdateExpression[?yield]
+ // 5) + UpdateExpression[?yield]
+ // 6) - UpdateExpression[?yield]
+ // 7) ~ UpdateExpression[?yield]
+ // 8) ! UpdateExpression[?yield]
+ unaryOperator := p.token
+ simpleUnaryExpression := p.parseSimpleUnaryExpression()
+ if p.token == SyntaxKindAsteriskAsteriskToken {
+ pos := skipTrivia(p.sourceText, simpleUnaryExpression.Pos())
+ end := simpleUnaryExpression.End()
+ if simpleUnaryExpression.kind == SyntaxKindTypeAssertionExpression {
+ p.parseErrorAt(pos, end, diagnostics.A_type_assertion_expression_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses)
+ } else {
+ //Debug.assert(isKeywordOrPunctuation(unaryOperator))
+ p.parseErrorAt(pos, end, diagnostics.An_unary_expression_with_the_0_operator_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, TokenToString(unaryOperator))
+ }
+ }
+ return simpleUnaryExpression
+}
+
+func (p *Parser) isUpdateExpression() bool {
+ switch p.token {
+ case SyntaxKindPlusToken, SyntaxKindMinusToken, SyntaxKindTildeToken, SyntaxKindExclamationToken, SyntaxKindDeleteKeyword, SyntaxKindTypeOfKeyword, SyntaxKindVoidKeyword, SyntaxKindAwaitKeyword:
+ return false
+ case SyntaxKindLessThanToken:
+ return p.languageVariant == LanguageVariantJSX
+ }
+ return true
+}
+
+func (p *Parser) parseUpdateExpression() *Expression {
+ pos := p.nodePos()
+ if p.token == SyntaxKindPlusPlusToken || p.token == SyntaxKindMinusMinusToken {
+ operator := p.token
+ p.nextToken()
+ result := p.factory.NewPrefixUnaryExpression(operator, p.parseLeftHandSideExpressionOrHigher())
+ p.finishNode(result, pos)
+ return result
+ } else if p.languageVariant == LanguageVariantJSX && p.token == SyntaxKindLessThanToken && p.lookAhead(p.nextTokenIsIdentifierOrKeywordOrGreaterThan) {
+ // JSXElement is part of primaryExpression
+ return p.parseJsxElementOrSelfClosingElementOrFragment(true /*inExpressionContext*/, -1 /*topInvalidNodePosition*/, nil /*openingTag*/, false /*mustBeUnary*/)
+ }
+ expression := p.parseLeftHandSideExpressionOrHigher()
+ if (p.token == SyntaxKindPlusPlusToken || p.token == SyntaxKindMinusMinusToken) && !p.hasPrecedingLineBreak() {
+ operator := p.token
+ p.nextToken()
+ result := p.factory.NewPostfixUnaryExpression(expression, operator)
+ p.finishNode(result, pos)
+ return result
+ }
+ return expression
+}
+
+func (p *Parser) parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext bool, topInvalidNodePosition int, openingTag *Node, mustBeUnary bool) *Expression {
+ pos := p.nodePos()
+ opening := p.parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext)
+ var result *Expression
+ switch opening.kind {
+ case SyntaxKindJsxOpeningElement:
+ children := p.parseJsxChildren(opening)
+ var closingElement *Node
+ lastChild := lastElement(children)
+ if lastChild != nil && lastChild.kind == SyntaxKindJsxElement &&
+ !tagNamesAreEquivalent(lastChild.AsJsxElement().openingElement.AsJsxOpeningElement().tagName, lastChild.AsJsxElement().closingElement.AsJsxClosingElement().tagName) &&
+ tagNamesAreEquivalent(opening.AsJsxOpeningElement().tagName, lastChild.AsJsxElement().closingElement.AsJsxClosingElement().tagName) {
+ // when an unclosed JsxOpeningElement incorrectly parses its parent's JsxClosingElement,
+ // restructure ((......
)) --> ((......>)
)
+ // (no need to error; the parent will error)
+ newClosingElement := p.factory.NewJsxClosingElement(p.createMissingIdentifier())
+ p.finishNode(newClosingElement, p.nodePos())
+ newLast := p.factory.NewJsxElement(lastChild.AsJsxElement().openingElement, lastChild.AsJsxElement().children, newClosingElement)
+ p.finishNode(newLast, lastChild.AsJsxElement().openingElement.Pos())
+ children = append(children[0:len(children)-1], newLast)
+ closingElement = lastChild.AsJsxElement().closingElement
+ } else {
+ closingElement = p.parseJsxClosingElement(opening, inExpressionContext)
+ if !tagNamesAreEquivalent(opening.AsJsxOpeningElement().tagName, closingElement.AsJsxClosingElement().tagName) {
+ if openingTag != nil && isJsxOpeningElement(openingTag) && tagNamesAreEquivalent(closingElement.AsJsxClosingElement().tagName, openingTag.AsJsxOpeningElement().tagName) {
+ // opening incorrectly matched with its parent's closing -- put error on opening
+ p.parseErrorAtRange(opening.AsJsxOpeningElement().tagName.loc, diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(p.sourceText, opening.AsJsxOpeningElement().tagName))
+ } else {
+ // other opening/closing mismatches -- put error on closing
+ p.parseErrorAtRange(closingElement.AsJsxClosingElement().tagName.loc, diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(p.sourceText, opening.AsJsxOpeningElement().tagName))
+ }
+ }
+ }
+ result = p.factory.NewJsxElement(opening, children, closingElement)
+ p.finishNode(result, pos)
+ case SyntaxKindJsxOpeningFragment:
+ result = p.factory.NewJsxFragment(opening, p.parseJsxChildren(opening), p.parseJsxClosingFragment(inExpressionContext))
+ p.finishNode(result, pos)
+ case SyntaxKindJsxSelfClosingElement:
+ // Nothing else to do for self-closing elements
+ result = opening
+ default:
+ panic("Unhandled case in parseJsxElementOrSelfClosingElementOrFragment")
+ }
+ // If the user writes the invalid code '' in an expression context (i.e. not wrapped in
+ // an enclosing tag), we'll naively try to parse ^ this as a 'less than' operator and the remainder of the tag
+ // as garbage, which will cause the formatter to badly mangle the JSX. Perform a speculative parse of a JSX
+ // element if we see a < token so that we can wrap it in a synthetic binary expression so the formatter
+ // does less damage and we can report a better error.
+ // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios
+ // of one sort or another.
+ // If we are in a unary context, we can't do this recovery; the binary expression we return here is not
+ // a valid UnaryExpression and will cause problems later.
+ if !mustBeUnary && inExpressionContext && p.token == SyntaxKindLessThanToken {
+ topBadPos := topInvalidNodePosition
+ if topBadPos < 0 {
+ topBadPos = result.Pos()
+ }
+ invalidElement := p.parseJsxElementOrSelfClosingElementOrFragment( /*inExpressionContext*/ true, topBadPos, nil, false)
+ operatorToken := p.factory.NewToken(SyntaxKindCommaToken)
+ operatorToken.loc = NewTextRange(invalidElement.Pos(), invalidElement.Pos())
+ p.parseErrorAt(skipTrivia(p.sourceText, topBadPos), invalidElement.End(), diagnostics.JSX_expressions_must_have_one_parent_element)
+ result = p.factory.NewBinaryExpression(result, operatorToken, invalidElement)
+ p.finishNode(result, pos)
+ }
+ return result
+}
+
+func (p *Parser) parseJsxChildren(openingTag *Expression) []*Expression {
+ saveParsingContexts := p.parsingContexts
+ p.parsingContexts |= 1 << PCJsxChildren
+ list := []*Expression{}
+ for {
+ currentToken := p.scanner.reScanJsxToken(true /*allowMultilineJsxText*/)
+ child := p.parseJsxChild(openingTag, currentToken)
+ if child == nil {
+ break
+ }
+ list = append(list, child)
+ if isJsxOpeningElement(openingTag) && child.kind == SyntaxKindJsxElement &&
+ !tagNamesAreEquivalent(child.AsJsxElement().openingElement.AsJsxOpeningElement().tagName, child.AsJsxElement().closingElement.AsJsxClosingElement().tagName) &&
+ tagNamesAreEquivalent(openingTag.AsJsxOpeningElement().tagName, child.AsJsxElement().closingElement.AsJsxClosingElement().tagName) {
+ // stop after parsing a mismatched child like ...(
) in order to reattach the higher
+ break
+ }
+ }
+ p.parsingContexts = saveParsingContexts
+ return list
+}
+
+func (p *Parser) parseJsxChild(openingTag *Node, token SyntaxKind) *Expression {
+ switch token {
+ case SyntaxKindEndOfFile:
+ // If we hit EOF, issue the error at the tag that lacks the closing element
+ // rather than at the end of the file (which is useless)
+ if isJsxOpeningFragment(openingTag) {
+ p.parseErrorAtRange(openingTag.loc, diagnostics.JSX_fragment_has_no_corresponding_closing_tag)
+ } else {
+ // We want the error span to cover only 'Foo.Bar' in < Foo.Bar >
+ // or to cover only 'Foo' in < Foo >
+ tag := openingTag.AsJsxOpeningElement().tagName
+ start := min(skipTrivia(p.sourceText, tag.Pos()), tag.End())
+ p.parseErrorAt(start, tag.End(), diagnostics.JSX_element_0_has_no_corresponding_closing_tag,
+ getTextOfNodeFromSourceText(p.sourceText, openingTag.AsJsxOpeningElement().tagName))
+ }
+ return nil
+ case SyntaxKindLessThanSlashToken, SyntaxKindConflictMarkerTrivia:
+ return nil
+ case SyntaxKindJsxText, SyntaxKindJsxTextAllWhiteSpaces:
+ return p.parseJsxText()
+ case SyntaxKindOpenBraceToken:
+ return p.parseJsxExpression(false /*inExpressionContext*/)
+ case SyntaxKindLessThanToken:
+ return p.parseJsxElementOrSelfClosingElementOrFragment(false /*inExpressionContext*/, -1 /*topInvalidNodePosition*/, openingTag, false)
+ }
+ panic("Unhandled case in parseJsxChild")
+}
+
+func (p *Parser) parseJsxText() *Node {
+ pos := p.nodePos()
+ result := p.factory.NewJsxText(p.scanner.tokenValue, p.token == SyntaxKindJsxTextAllWhiteSpaces)
+ p.scanJsxText()
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseJsxExpression(inExpressionContext bool) *Node {
+ pos := p.nodePos()
+ if !p.parseExpected(SyntaxKindOpenBraceToken) {
+ return nil
+ }
+ var dotDotDotToken *Node
+ var expression *Expression
+ if p.token != SyntaxKindCloseBraceToken {
+ if !inExpressionContext {
+ dotDotDotToken = p.parseOptionalToken(SyntaxKindDotDotDotToken)
+ }
+ // Only an AssignmentExpression is valid here per the JSX spec,
+ // but we can unambiguously parse a comma sequence and provide
+ // a better error message in grammar checking.
+ expression = p.parseExpression()
+ }
+ if inExpressionContext {
+ p.parseExpected(SyntaxKindCloseBraceToken)
+ } else if p.parseExpectedWithoutAdvancing(SyntaxKindCloseBraceToken) {
+ p.scanJsxText()
+ }
+ result := p.factory.NewJsxExpression(dotDotDotToken, expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) scanJsxText() SyntaxKind {
+ p.token = p.scanner.scanJsxToken()
+ return p.token
+}
+
+func (p *Parser) scanJsxIdentifier() SyntaxKind {
+ p.token = p.scanner.scanJsxIdentifier()
+ return p.token
+}
+
+func (p *Parser) scanJsxAttributeValue() SyntaxKind {
+ p.token = p.scanner.scanJsxAttributeValue()
+ return p.token
+}
+
+func (p *Parser) parseJsxClosingElement(open *Node, inExpressionContext bool) *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindLessThanSlashToken)
+ tagName := p.parseJsxElementName()
+ if p.parseExpectedWithDiagnostic(SyntaxKindGreaterThanToken, nil /*diagnosticMessage*/, false /*shouldAdvance*/) {
+ // manually advance the scanner in order to look for jsx text inside jsx
+ if inExpressionContext || !tagNamesAreEquivalent(open.AsJsxOpeningElement().tagName, tagName) {
+ p.nextToken()
+ } else {
+ p.scanJsxText()
+ }
+ }
+ result := p.factory.NewJsxClosingElement(tagName)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext bool) *Expression {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindLessThanToken)
+ if p.token == SyntaxKindGreaterThanToken {
+ // See below for explanation of scanJsxText
+ p.scanJsxText()
+ result := p.factory.NewJsxOpeningFragment()
+ p.finishNode(result, pos)
+ return result
+ }
+ tagName := p.parseJsxElementName()
+ var typeArguments *Node
+ if p.contextFlags&NodeFlagsJavaScriptFile == 0 {
+ typeArguments = p.parseTypeArguments()
+ }
+ attributes := p.parseJsxAttributes()
+ var result *Expression
+ if p.token == SyntaxKindGreaterThanToken {
+ // Closing tag, so scan the immediately-following text with the JSX scanning instead
+ // of regular scanning to avoid treating illegal characters (e.g. '#') as immediate
+ // scanning errors
+ p.scanJsxText()
+ result = p.factory.NewJsxOpeningElement(tagName, typeArguments, attributes)
+ } else {
+ p.parseExpected(SyntaxKindSlashToken)
+ if p.parseExpectedWithoutAdvancing(SyntaxKindGreaterThanToken) {
+ if inExpressionContext {
+ p.nextToken()
+ } else {
+ p.scanJsxText()
+ }
+ }
+ result = p.factory.NewJsxSelfClosingElement(tagName, typeArguments, attributes)
+ }
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseJsxElementName() *Expression {
+ pos := p.nodePos()
+ // JsxElement can have name in the form of
+ // propertyAccessExpression
+ // primaryExpression in the form of an identifier and "this" keyword
+ // We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword
+ // We only want to consider "this" as a primaryExpression
+ initialExpression := p.parseJsxTagName()
+ if isJsxNamespacedName(initialExpression) {
+ return initialExpression // `a:b.c` is invalid syntax, don't even look for the `.` if we parse `a:b`, and let `parseAttribute` report "unexpected :" instead.
+ }
+ expression := initialExpression
+ for p.parseOptional(SyntaxKindDotToken) {
+ expression = p.factory.NewPropertyAccessExpression(expression, nil, p.parseRightSideOfDot(true /*allowIdentifierNames*/, false /*allowPrivateIdentifiers*/, false /*allowUnicodeEscapeSequenceInIdentifierName*/), NodeFlagsNone)
+ p.finishNode(expression, pos)
+ }
+ return expression
+}
+
+func (p *Parser) parseJsxTagName() *Expression {
+ pos := p.nodePos()
+ p.scanJsxIdentifier()
+ isThis := p.token == SyntaxKindThisKeyword
+ tagName := p.parseIdentifierNameErrorOnUnicodeEscapeSequence()
+ if p.parseOptional(SyntaxKindColonToken) {
+ p.scanJsxIdentifier()
+ result := p.factory.NewJsxNamespacedName(tagName, p.parseIdentifierNameErrorOnUnicodeEscapeSequence())
+ p.finishNode(result, pos)
+ return result
+ }
+ if isThis {
+ result := p.factory.NewKeywordExpression(SyntaxKindThisKeyword)
+ p.finishNode(result, pos)
+ return result
+ }
+ return tagName
+}
+
+func (p *Parser) parseJsxAttributes() *Node {
+ pos := p.nodePos()
+ result := p.factory.NewJsxAttributes(parseList(p, PCJsxAttributes, p.parseJsxAttribute))
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseJsxAttribute() *Node {
+ if p.token == SyntaxKindOpenBraceToken {
+ return p.parseJsxSpreadAttribute()
+ }
+ pos := p.nodePos()
+ result := p.factory.NewJsxAttribute(p.parseJsxAttributeName(), p.parseJsxAttributeValue())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseJsxSpreadAttribute() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindOpenBraceToken)
+ p.parseExpected(SyntaxKindDotDotDotToken)
+ expression := p.parseExpression()
+ p.parseExpected(SyntaxKindCloseBraceToken)
+ result := p.factory.NewJsxSpreadAttribute(expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseJsxAttributeName() *Node {
+ pos := p.nodePos()
+ p.scanJsxIdentifier()
+ attrName := p.parseIdentifierNameErrorOnUnicodeEscapeSequence()
+ if p.parseOptional(SyntaxKindColonToken) {
+ p.scanJsxIdentifier()
+ result := p.factory.NewJsxNamespacedName(attrName, p.parseIdentifierNameErrorOnUnicodeEscapeSequence())
+ p.finishNode(result, pos)
+ return result
+ }
+ return attrName
+}
+
+func (p *Parser) parseJsxAttributeValue() *Expression {
+ if p.token == SyntaxKindEqualsToken {
+ if p.scanJsxAttributeValue() == SyntaxKindStringLiteral {
+ return p.parseLiteralExpression()
+ }
+ if p.token == SyntaxKindOpenBraceToken {
+ return p.parseJsxExpression( /*inExpressionContext*/ true)
+ }
+ if p.token == SyntaxKindLessThanToken {
+ return p.parseJsxElementOrSelfClosingElementOrFragment(true /*inExpressionContext*/, -1, nil, false)
+ }
+ p.parseErrorAtCurrentToken(diagnostics.X_or_JSX_element_expected)
+ }
+ return nil
+}
+
+func (p *Parser) parseJsxClosingFragment(inExpressionContext bool) *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindLessThanSlashToken)
+ if p.parseExpectedWithDiagnostic(SyntaxKindGreaterThanToken, diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment, false /*shouldAdvance*/) {
+ // manually advance the scanner in order to look for jsx text inside jsx
+ if inExpressionContext {
+ p.nextToken()
+ } else {
+ p.scanJsxText()
+ }
+ }
+ result := p.factory.NewJsxClosingFragment()
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseSimpleUnaryExpression() *Expression {
+ switch p.token {
+ case SyntaxKindPlusToken, SyntaxKindMinusToken, SyntaxKindTildeToken, SyntaxKindExclamationToken:
+ return p.parsePrefixUnaryExpression()
+ case SyntaxKindDeleteKeyword:
+ return p.parseDeleteExpression()
+ case SyntaxKindTypeOfKeyword:
+ return p.parseTypeOfExpression()
+ case SyntaxKindVoidKeyword:
+ return p.parseVoidExpression()
+ case SyntaxKindLessThanToken:
+ // !!!
+ // // Just like in parseUpdateExpression, we need to avoid parsing type assertions when
+ // // in JSX and we see an expression like "+ bar".
+ // if (languageVariant == LanguageVariant.JSX) {
+ // return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, /*topInvalidNodePosition*/ undefined, /*openingTag*/ undefined, /*mustBeUnary*/ true);
+ // }
+ // // This is modified UnaryExpression grammar in TypeScript
+ // // UnaryExpression (modified):
+ // // < type > UnaryExpression
+ return p.parseTypeAssertion()
+ case SyntaxKindAwaitKeyword:
+ if p.isAwaitExpression() {
+ return p.parseAwaitExpression()
+ }
+ fallthrough
+ default:
+ return p.parseUpdateExpression()
+ }
+}
+
+func (p *Parser) parsePrefixUnaryExpression() *Node {
+ pos := p.nodePos()
+ operator := p.token
+ p.nextToken()
+ result := p.factory.NewPrefixUnaryExpression(operator, p.parseSimpleUnaryExpression())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseDeleteExpression() *Node {
+ pos := p.nodePos()
+ p.nextToken()
+ result := p.factory.NewDeleteExpression(p.parseSimpleUnaryExpression())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTypeOfExpression() *Node {
+ pos := p.nodePos()
+ p.nextToken()
+ result := p.factory.NewTypeOfExpression(p.parseSimpleUnaryExpression())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseVoidExpression() *Node {
+ pos := p.nodePos()
+ p.nextToken()
+ result := p.factory.NewVoidExpression(p.parseSimpleUnaryExpression())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) isAwaitExpression() bool {
+ if p.token == SyntaxKindAwaitKeyword {
+ if p.inAwaitContext() {
+ return true
+ }
+ // here we are using similar heuristics as 'isYieldExpression'
+ return p.lookAhead(p.nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine)
+ }
+ return false
+}
+
+func (p *Parser) parseAwaitExpression() *Node {
+ pos := p.nodePos()
+ p.nextToken()
+ result := p.factory.NewAwaitExpression(p.parseSimpleUnaryExpression())
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTypeAssertion() *Node {
+ // !!! Debug.assert(languageVariant !== LanguageVariant.JSX, "Type assertions should never be parsed in JSX; they should be parsed as comparisons or JSX elements/fragments.");
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindLessThanToken)
+ typeNode := p.parseType()
+ p.parseExpected(SyntaxKindGreaterThanToken)
+ expression := p.parseSimpleUnaryExpression()
+ result := p.factory.NewTypeAssertion(typeNode, expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseLeftHandSideExpressionOrHigher() *Expression {
+ // Original Ecma:
+ // LeftHandSideExpression: See 11.2
+ // NewExpression
+ // CallExpression
+ //
+ // Our simplification:
+ //
+ // LeftHandSideExpression: See 11.2
+ // MemberExpression
+ // CallExpression
+ //
+ // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with
+ // MemberExpression to make our lives easier.
+ //
+ // to best understand the below code, it's important to see how CallExpression expands
+ // out into its own productions:
+ //
+ // CallExpression:
+ // MemberExpression Arguments
+ // CallExpression Arguments
+ // CallExpression[Expression]
+ // CallExpression.IdentifierName
+ // import (AssignmentExpression)
+ // super Arguments
+ // super.IdentifierName
+ //
+ // Because of the recursion in these calls, we need to bottom out first. There are three
+ // bottom out states we can run into: 1) We see 'super' which must start either of
+ // the last two CallExpression productions. 2) We see 'import' which must start import call.
+ // 3)we have a MemberExpression which either completes the LeftHandSideExpression,
+ // or starts the beginning of the first four CallExpression productions.
+ pos := p.nodePos()
+ var expression *Expression
+ if p.token == SyntaxKindImportKeyword {
+ if p.lookAhead(p.nextTokenIsOpenParenOrLessThan) {
+ // We don't want to eagerly consume all import keyword as import call expression so we look ahead to find "("
+ // For example:
+ // var foo3 = require("subfolder
+ // import * as foo1 from "module-from-node
+ // We want this import to be a statement rather than import call expression
+ p.sourceFlags |= NodeFlagsPossiblyContainsDynamicImport
+ expression = p.parseKeywordExpression()
+ } else if p.lookAhead(p.nextTokenIsDot) {
+ // This is an 'import.*' metaproperty (i.e. 'import.meta')
+ p.nextToken() // advance past the 'import'
+ p.nextToken() // advance past the dot
+ expression = p.factory.NewMetaProperty(SyntaxKindImportKeyword, p.parseIdentifierName())
+ p.finishNode(expression, pos)
+ p.sourceFlags |= NodeFlagsPossiblyContainsImportMeta
+ } else {
+ expression = p.parseMemberExpressionOrHigher()
+ }
+ } else if p.token == SyntaxKindSuperKeyword {
+ expression = p.parseSuperExpression()
+ } else {
+ expression = p.parseMemberExpressionOrHigher()
+ }
+ // Now, we *may* be complete. However, we might have consumed the start of a
+ // CallExpression or OptionalExpression. As such, we need to consume the rest
+ // of it here to be complete.
+ return p.parseCallExpressionRest(pos, expression)
+}
+
+func (p *Parser) nextTokenIsDot() bool {
+ return p.nextToken() == SyntaxKindDotToken
+}
+
+func (p *Parser) parseSuperExpression() *Expression {
+ pos := p.nodePos()
+ expression := p.parseKeywordExpression()
+ if p.token == SyntaxKindLessThanToken {
+ startPos := p.nodePos()
+ typeArguments := p.tryParseTypeArgumentsInExpression()
+ if typeArguments != nil {
+ p.parseErrorAt(startPos, p.nodePos(), diagnostics.X_super_may_not_use_type_arguments)
+ if !p.isTemplateStartOfTaggedTemplate() {
+ expression := p.factory.NewExpressionWithTypeArguments(expression, typeArguments)
+ p.finishNode(expression, pos)
+ }
+ }
+ }
+ if p.token == SyntaxKindOpenParenToken || p.token == SyntaxKindDotToken || p.token == SyntaxKindOpenBracketToken {
+ return expression
+ }
+ // If we have seen "super" it must be followed by '(' or '.'.
+ // If it wasn't then just try to parse out a '.' and report an error.
+ p.parseErrorAtCurrentToken(diagnostics.X_super_must_be_followed_by_an_argument_list_or_member_access)
+ // private names will never work with `super` (`super.#foo`), but that's a semantic error, not syntactic
+ result := p.factory.NewPropertyAccessExpression(expression, nil /*questionDotToken*/, p.parseRightSideOfDot(true /*allowIdentifierNames*/, true /*allowPrivateIdentifiers*/, true /*allowUnicodeEscapeSequenceInIdentifierName*/), NodeFlagsNone)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) isTemplateStartOfTaggedTemplate() bool {
+ return p.token == SyntaxKindNoSubstitutionTemplateLiteral || p.token == SyntaxKindTemplateHead
+}
+
+func (p *Parser) tryParseTypeArgumentsInExpression() *Node {
+ // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators.
+ state := p.mark()
+ if p.contextFlags&NodeFlagsJavaScriptFile == 0 && p.reScanLessThanToken() == SyntaxKindLessThanToken {
+ pos := p.nodePos()
+ p.nextToken()
+ typeArguments := parseDelimitedList(p, PCTypeArguments, p.parseType)
+ // If it doesn't have the closing `>` then it's definitely not an type argument list.
+ if p.reScanGreaterThanToken() == SyntaxKindGreaterThanToken {
+ p.nextToken()
+ // We successfully parsed a type argument list. The next token determines whether we want to
+ // treat it as such. If the type argument list is followed by `(` or a template literal, as in
+ // `f(42)`, we favor the type argument interpretation even though JavaScript would view
+ // it as a relational expression.
+ if p.canFollowTypeArgumentsInExpression() {
+ result := p.factory.NewTypeArgumentList(typeArguments)
+ p.finishNode(result, pos)
+ return result
+ }
+ }
+ }
+ p.rewind(state)
+ return nil
+}
+
+func (p *Parser) canFollowTypeArgumentsInExpression() bool {
+ switch p.token {
+ // These tokens can follow a type argument list in a call expression:
+ // foo(
+ // foo `...`
+ // foo `...${100}...`
+ case SyntaxKindOpenParenToken, SyntaxKindNoSubstitutionTemplateLiteral, SyntaxKindTemplateHead:
+ return true
+ // A type argument list followed by `<` never makes sense, and a type argument list followed
+ // by `>` is ambiguous with a (re-scanned) `>>` operator, so we disqualify both. Also, in
+ // this context, `+` and `-` are unary operators, not binary operators.
+ case SyntaxKindLessThanToken, SyntaxKindGreaterThanToken, SyntaxKindPlusToken, SyntaxKindMinusToken:
+ return false
+ }
+ // We favor the type argument list interpretation when it is immediately followed by
+ // a line break, a binary operator, or something that can't start an expression.
+ return p.hasPrecedingLineBreak() || p.isBinaryOperator() || !p.isStartOfExpression()
+}
+
+func (p *Parser) parseMemberExpressionOrHigher() *Node {
+ // Note: to make our lives simpler, we decompose the NewExpression productions and
+ // place ObjectCreationExpression and FunctionExpression into PrimaryExpression.
+ // like so:
+ //
+ // PrimaryExpression : See 11.1
+ // this
+ // Identifier
+ // Literal
+ // ArrayLiteral
+ // ObjectLiteral
+ // (Expression)
+ // FunctionExpression
+ // new MemberExpression Arguments?
+ //
+ // MemberExpression : See 11.2
+ // PrimaryExpression
+ // MemberExpression[Expression]
+ // MemberExpression.IdentifierName
+ //
+ // CallExpression : See 11.2
+ // MemberExpression
+ // CallExpression Arguments
+ // CallExpression[Expression]
+ // CallExpression.IdentifierName
+ //
+ // Technically this is ambiguous. i.e. CallExpression defines:
+ //
+ // CallExpression:
+ // CallExpression Arguments
+ //
+ // If you see: "new Foo()"
+ //
+ // Then that could be treated as a single ObjectCreationExpression, or it could be
+ // treated as the invocation of "new Foo". We disambiguate that in code (to match
+ // the original grammar) by making sure that if we see an ObjectCreationExpression
+ // we always consume arguments if they are there. So we treat "new Foo()" as an
+ // object creation only, and not at all as an invocation. Another way to think
+ // about this is that for every "new" that we see, we will consume an argument list if
+ // it is there as part of the *associated* object creation node. Any additional
+ // argument lists we see, will become invocation expressions.
+ //
+ // Because there are no other places in the grammar now that refer to FunctionExpression
+ // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression
+ // production.
+ //
+ // Because CallExpression and MemberExpression are left recursive, we need to bottom out
+ // of the recursion immediately. So we parse out a primary expression to start with.
+ pos := p.nodePos()
+ expression := p.parsePrimaryExpression()
+ return p.parseMemberExpressionRest(pos, expression, true /*allowOptionalChain*/)
+}
+
+func (p *Parser) parseMemberExpressionRest(pos int, expression *Expression, allowOptionalChain bool) *Expression {
+ for {
+ var questionDotToken *Node
+ isPropertyAccess := false
+ if allowOptionalChain && p.isStartOfOptionalPropertyOrElementAccessChain() {
+ questionDotToken = p.parseExpectedToken(SyntaxKindQuestionDotToken)
+ isPropertyAccess = tokenIsIdentifierOrKeyword(p.token)
+ } else {
+ isPropertyAccess = p.parseOptional(SyntaxKindDotToken)
+ }
+ if isPropertyAccess {
+ expression = p.parsePropertyAccessExpressionRest(pos, expression, questionDotToken)
+ continue
+ }
+ // when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName
+ if (questionDotToken != nil || !p.inDecoratorContext()) && p.parseOptional(SyntaxKindOpenBracketToken) {
+ expression = p.parseElementAccessExpressionRest(pos, expression, questionDotToken)
+ continue
+ }
+ if p.isTemplateStartOfTaggedTemplate() {
+ // Absorb type arguments into TemplateExpression when preceding expression is ExpressionWithTypeArguments
+ if questionDotToken == nil && isExpressionWithTypeArguments(expression) {
+ expression = p.parseTaggedTemplateRest(pos, expression.AsExpressionWithTypeArguments().expression, questionDotToken, expression.AsExpressionWithTypeArguments().typeArguments)
+ } else {
+ expression = p.parseTaggedTemplateRest(pos, expression, questionDotToken, nil /*typeArguments*/)
+ }
+ continue
+ }
+ if questionDotToken == nil {
+ if p.token == SyntaxKindExclamationToken && !p.hasPrecedingLineBreak() {
+ p.nextToken()
+ expression = p.factory.NewNonNullExpression(expression)
+ p.finishNode(expression, pos)
+ continue
+ }
+ typeArguments := p.tryParseTypeArgumentsInExpression()
+ if typeArguments != nil {
+ expression = p.factory.NewExpressionWithTypeArguments(expression, typeArguments)
+ p.finishNode(expression, pos)
+ continue
+ }
+ }
+ return expression
+ }
+}
+
+func (p *Parser) isStartOfOptionalPropertyOrElementAccessChain() bool {
+ return p.token == SyntaxKindQuestionDotToken && p.lookAhead(p.nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate)
+}
+
+func (p *Parser) nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate() bool {
+ p.nextToken()
+ return tokenIsIdentifierOrKeyword(p.token) || p.token == SyntaxKindOpenBracketToken || p.isTemplateStartOfTaggedTemplate()
+}
+
+func (p *Parser) parsePropertyAccessExpressionRest(pos int, expression *Expression, questionDotToken *Node) *Node {
+ name := p.parseRightSideOfDot(true /*allowIdentifierNames*/, true /*allowPrivateIdentifiers*/, true /*allowUnicodeEscapeSequenceInIdentifierName*/)
+ isOptionalChain := questionDotToken != nil || p.tryReparseOptionalChain(expression)
+ propertyAccess := p.factory.NewPropertyAccessExpression(expression, questionDotToken, name, ifElse(isOptionalChain, NodeFlagsOptionalChain, NodeFlagsNone))
+ if isOptionalChain && isPrivateIdentifier(name) {
+ p.parseErrorAtRange(p.skipRangeTrivia(name.loc), diagnostics.An_optional_chain_cannot_contain_private_identifiers)
+ }
+ if isExpressionWithTypeArguments(expression) && expression.AsExpressionWithTypeArguments().typeArguments != nil {
+ loc := p.skipRangeTrivia(expression.AsExpressionWithTypeArguments().typeArguments.loc)
+ p.parseErrorAtRange(loc, diagnostics.An_instantiation_expression_cannot_be_followed_by_a_property_access)
+ }
+ p.finishNode(propertyAccess, pos)
+ return propertyAccess
+}
+
+func (p *Parser) tryReparseOptionalChain(node *Expression) bool {
+ if node.flags&NodeFlagsOptionalChain != 0 {
+ return true
+ }
+ // check for an optional chain in a non-null expression
+ if isNonNullExpression(node) {
+ expr := node.AsNonNullExpression().expression
+ for isNonNullExpression(expr) && expr.flags&NodeFlagsOptionalChain == 0 {
+ expr = expr.AsNonNullExpression().expression
+ }
+ if expr.flags&NodeFlagsOptionalChain != 0 {
+ // this is part of an optional chain. Walk down from `node` to `expression` and set the flag.
+ for isNonNullExpression(node) {
+ node.flags |= NodeFlagsOptionalChain
+ node = node.AsNonNullExpression().expression
+ }
+ return true
+ }
+ }
+ return false
+}
+
+func (p *Parser) parseElementAccessExpressionRest(pos int, expression *Expression, questionDotToken *Node) *Node {
+ var argumentExpression *Expression
+ if p.token == SyntaxKindCloseBracketToken {
+ p.parseErrorAt(p.nodePos(), p.nodePos(), diagnostics.An_element_access_expression_should_take_an_argument)
+ argumentExpression = p.createMissingIdentifier()
+ } else {
+ argument := p.parseExpressionAllowIn()
+ if isStringOrNumericLiteralLike(argument) {
+ p.internIdentifier(getTextOfIdentifierOrLiteral(argument))
+ }
+ argumentExpression = argument
+ }
+ p.parseExpected(SyntaxKindCloseBracketToken)
+ isOptionalChain := questionDotToken != nil || p.tryReparseOptionalChain(expression)
+ elementAccess := p.factory.NewElementAccessExpression(expression, questionDotToken, argumentExpression, ifElse(isOptionalChain, NodeFlagsOptionalChain, NodeFlagsNone))
+ p.finishNode(elementAccess, pos)
+ return elementAccess
+}
+
+func (p *Parser) parseCallExpressionRest(pos int, expression *Expression) *Expression {
+ for {
+ expression = p.parseMemberExpressionRest(pos, expression /*allowOptionalChain*/, true)
+ var typeArguments *Node
+ questionDotToken := p.parseOptionalToken(SyntaxKindQuestionDotToken)
+ if questionDotToken != nil {
+ typeArguments = p.tryParseTypeArgumentsInExpression()
+ if p.isTemplateStartOfTaggedTemplate() {
+ expression = p.parseTaggedTemplateRest(pos, expression, questionDotToken, typeArguments)
+ continue
+ }
+ }
+ if typeArguments != nil || p.token == SyntaxKindOpenParenToken {
+ // Absorb type arguments into CallExpression when preceding expression is ExpressionWithTypeArguments
+ if questionDotToken == nil && expression.kind == SyntaxKindExpressionWithTypeArguments {
+ typeArguments = expression.AsExpressionWithTypeArguments().typeArguments
+ expression = expression.AsExpressionWithTypeArguments().expression
+ }
+ argumentList := p.parseArgumentList()
+ isOptionalChain := questionDotToken != nil || p.tryReparseOptionalChain(expression)
+ expression = p.factory.NewCallExpression(expression, questionDotToken, typeArguments, argumentList, ifElse(isOptionalChain, NodeFlagsOptionalChain, NodeFlagsNone))
+ p.finishNode(expression, pos)
+ continue
+ }
+ if questionDotToken != nil {
+ // We parsed `?.` but then failed to parse anything, so report a missing identifier here.
+ p.parseErrorAtCurrentToken(diagnostics.Identifier_expected)
+ expression = p.createMissingIdentifier()
+ p.finishNode(expression, pos)
+ }
+ break
+ }
+ return expression
+}
+
+func (p *Parser) parseArgumentList() []*Expression {
+ p.parseExpected(SyntaxKindOpenParenToken)
+ result := parseDelimitedList(p, PCArgumentExpressions, p.parseArgumentExpression)
+ p.parseExpected(SyntaxKindCloseParenToken)
+ return result
+}
+
+func (p *Parser) parseArgumentExpression() *Expression {
+ return doInContext(p, NodeFlagsDisallowInContext|NodeFlagsDecoratorContext, false, p.parseArgumentOrArrayLiteralElement)
+}
+
+func (p *Parser) parseArgumentOrArrayLiteralElement() *Expression {
+ switch p.token {
+ case SyntaxKindDotDotDotToken:
+ return p.parseSpreadElement()
+ case SyntaxKindCommaToken:
+ result := p.factory.NewOmittedExpression()
+ p.finishNode(result, p.nodePos())
+ return result
+ }
+ return p.parseAssignmentExpressionOrHigher()
+}
+
+func (p *Parser) parseSpreadElement() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindDotDotDotToken)
+ expression := p.parseAssignmentExpressionOrHigher()
+ result := p.factory.NewSpreadElement(expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTaggedTemplateRest(pos int, tag *Expression, questionDotToken *Node, typeArguments *Node) *Node {
+ var template *Expression
+ if p.token == SyntaxKindNoSubstitutionTemplateLiteral {
+ p.reScanTemplateToken(true /*isTaggedTemplate*/)
+ template = p.parseLiteralExpression()
+ } else {
+ template = p.parseTemplateExpression(true /*isTaggedTemplate*/)
+ }
+ isOptionalChain := questionDotToken != nil || tag.flags&NodeFlagsOptionalChain != 0
+ result := p.factory.NewTaggedTemplateExpression(tag, questionDotToken, typeArguments, template, ifElse(isOptionalChain, NodeFlagsOptionalChain, NodeFlagsNone))
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTemplateExpression(isTaggedTemplate bool) *Expression {
+ pos := p.nodePos()
+ result := p.factory.NewTemplateExpression(p.parseTemplateHead(isTaggedTemplate), p.parseTemplateSpans(isTaggedTemplate))
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseTemplateSpans(isTaggedTemplate bool) []*Node {
+ list := []*Node{}
+ for {
+ span := p.parseTemplateSpan(isTaggedTemplate)
+ list = append(list, span)
+ if span.AsTemplateSpan().literal.kind != SyntaxKindTemplateMiddle {
+ break
+ }
+ }
+ return list
+}
+
+func (p *Parser) parseTemplateSpan(isTaggedTemplate bool) *Node {
+ pos := p.nodePos()
+ expression := p.parseExpressionAllowIn()
+ literal := p.parseLiteralOfTemplateSpan(isTaggedTemplate)
+ result := p.factory.NewTemplateSpan(expression, literal)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parsePrimaryExpression() *Expression {
+ switch p.token {
+ case SyntaxKindNoSubstitutionTemplateLiteral:
+ if p.scanner.tokenFlags&TokenFlagsIsInvalid != 0 {
+ p.reScanTemplateToken(false /*isTaggedTemplate*/)
+ }
+ fallthrough
+ case SyntaxKindNumericLiteral, SyntaxKindBigintLiteral, SyntaxKindStringLiteral:
+ return p.parseLiteralExpression()
+ case SyntaxKindThisKeyword, SyntaxKindSuperKeyword, SyntaxKindNullKeyword, SyntaxKindTrueKeyword, SyntaxKindFalseKeyword:
+ return p.parseKeywordExpression()
+ case SyntaxKindOpenParenToken:
+ return p.parseParenthesizedExpression()
+ case SyntaxKindOpenBracketToken:
+ return p.parseArrayLiteralExpression()
+ case SyntaxKindOpenBraceToken:
+ return p.parseObjectLiteralExpression()
+ case SyntaxKindAsyncKeyword:
+ // Async arrow functions are parsed earlier in parseAssignmentExpressionOrHigher.
+ // If we encounter `async [no LineTerminator here] function` then this is an async
+ // function; otherwise, its an identifier.
+ if !p.lookAhead(p.nextTokenIsFunctionKeywordOnSameLine) {
+ break
+ }
+ return p.parseFunctionExpression()
+ case SyntaxKindAtToken:
+ return p.parseDecoratedExpression()
+ case SyntaxKindClassKeyword:
+ return p.parseClassExpression()
+ case SyntaxKindFunctionKeyword:
+ return p.parseFunctionExpression()
+ case SyntaxKindNewKeyword:
+ return p.parseNewExpressionOrNewDotTarget()
+ case SyntaxKindSlashToken, SyntaxKindSlashEqualsToken:
+ if p.reScanSlashToken() == SyntaxKindRegularExpressionLiteral {
+ return p.parseLiteralExpression()
+ }
+ case SyntaxKindTemplateHead:
+ return p.parseTemplateExpression(false /*isTaggedTemplate*/)
+ case SyntaxKindPrivateIdentifier:
+ return p.parsePrivateIdentifier()
+ }
+ return p.parseIdentifierWithDiagnostic(diagnostics.Expression_expected, nil)
+}
+
+func (p *Parser) parseParenthesizedExpression() *Expression {
+ pos := p.nodePos()
+ // !!! JSDoc
+ p.parseExpected(SyntaxKindOpenParenToken)
+ expression := p.parseExpressionAllowIn()
+ p.parseExpected(SyntaxKindCloseParenToken)
+ result := p.factory.NewParenthesizedExpression(expression)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseArrayLiteralExpression() *Expression {
+ pos := p.nodePos()
+ openBracketPosition := p.scanner.TokenStart()
+ openBracketParsed := p.parseExpected(SyntaxKindOpenBracketToken)
+ multiLine := p.hasPrecedingLineBreak()
+ elements := parseDelimitedList(p, PCArrayLiteralMembers, p.parseArgumentOrArrayLiteralElement)
+ p.parseExpectedMatchingBrackets(SyntaxKindOpenBracketToken, SyntaxKindCloseBracketToken, openBracketParsed, openBracketPosition)
+ result := p.factory.NewArrayLiteralExpression(elements, multiLine)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseObjectLiteralExpression() *Expression {
+ pos := p.nodePos()
+ openBracePosition := p.scanner.TokenStart()
+ openBraceParsed := p.parseExpected(SyntaxKindOpenBraceToken)
+ multiLine := p.hasPrecedingLineBreak()
+ properties := parseDelimitedList(p, PCObjectLiteralMembers, p.parseObjectLiteralElement)
+ p.parseExpectedMatchingBrackets(SyntaxKindOpenBraceToken, SyntaxKindCloseBraceToken, openBraceParsed, openBracePosition)
+ result := p.factory.NewObjectLiteralExpression(properties, multiLine)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseObjectLiteralElement() *Node {
+ pos := p.nodePos()
+ hasJSDoc := p.hasPrecedingJSDocComment()
+ if p.parseOptional(SyntaxKindDotDotDotToken) {
+ expression := p.parseAssignmentExpressionOrHigher()
+ result := p.factory.NewSpreadAssignment(expression)
+ p.finishNode(result, pos)
+ return result
+ }
+ modifiers := p.parseModifiersWithOptions(true /*allowDecorators*/, false /*permitConstAsModifier*/, false /*stopOnStartOfClassStaticBlock*/)
+ if p.parseContextualModifier(SyntaxKindGetKeyword) {
+ return p.parseAccessorDeclaration(pos, hasJSDoc, modifiers, SyntaxKindGetAccessor, SignatureFlagsNone)
+ }
+ if p.parseContextualModifier(SyntaxKindSetKeyword) {
+ return p.parseAccessorDeclaration(pos, hasJSDoc, modifiers, SyntaxKindSetAccessor, SignatureFlagsNone)
+ }
+ asteriskToken := p.parseOptionalToken(SyntaxKindAsteriskToken)
+ tokenIsIdentifier := p.isIdentifier()
+ name := p.parsePropertyName()
+ // Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker.
+ postfixToken := p.parseOptionalToken(SyntaxKindQuestionToken)
+ // Decorators, Modifiers, questionToken, and exclamationToken are not supported by property assignments and are reported in the grammar checker
+ if postfixToken == nil {
+ postfixToken = p.parseOptionalToken(SyntaxKindExclamationToken)
+ }
+ if asteriskToken != nil || p.token == SyntaxKindOpenParenToken || p.token == SyntaxKindLessThanToken {
+ return p.parseMethodDeclaration(pos, hasJSDoc, modifiers, asteriskToken, name, postfixToken, nil /*diagnosticMessage*/)
+ }
+ // check if it is short-hand property assignment or normal property assignment
+ // NOTE: if token is EqualsToken it is interpreted as CoverInitializedName production
+ // CoverInitializedName[Yield] :
+ // IdentifierReference[?Yield] Initializer[In, ?Yield]
+ // this is necessary because ObjectLiteral productions are also used to cover grammar for ObjectAssignmentPattern
+ var node *Node
+ isShorthandPropertyAssignment := tokenIsIdentifier && p.token != SyntaxKindColonToken
+ if isShorthandPropertyAssignment {
+ var initializer *Expression
+ if p.parseOptional(SyntaxKindEqualsToken) {
+ initializer = doInContext(p, NodeFlagsDisallowInContext, false, p.parseAssignmentExpressionOrHigher)
+ }
+ node = p.factory.NewShorthandPropertyAssignment(modifiers, name, postfixToken, initializer)
+ } else {
+ p.parseExpected(SyntaxKindColonToken)
+ initializer := doInContext(p, NodeFlagsDisallowInContext, false, p.parseAssignmentExpressionOrHigher)
+ node = p.factory.NewPropertyAssignment(modifiers, name, postfixToken, initializer)
+ }
+ p.finishNode(node, pos)
+ return node
+}
+
+func (p *Parser) parseFunctionExpression() *Expression {
+ // GeneratorExpression:
+ // function* BindingIdentifier [Yield][opt](FormalParameters[Yield]){ GeneratorBody }
+ //
+ // FunctionExpression:
+ // function BindingIdentifier[opt](FormalParameters){ FunctionBody }
+ saveContexFlags := p.contextFlags
+ p.setContextFlags(NodeFlagsDecoratorContext, false)
+ pos := p.nodePos()
+ // !!! JSDoc
+ modifiers := p.parseModifiers()
+ p.parseExpected(SyntaxKindFunctionKeyword)
+ asteriskToken := p.parseOptionalToken(SyntaxKindAsteriskToken)
+ isGenerator := asteriskToken != nil
+ isAsync := hasAsyncModifier(modifiers)
+ signatureFlags := ifElse(isGenerator, SignatureFlagsYield, SignatureFlagsNone) | ifElse(isAsync, SignatureFlagsAwait, SignatureFlagsNone)
+ var name *Node
+ switch {
+ case isGenerator && isAsync:
+ name = doInContext(p, NodeFlagsYieldContext|NodeFlagsAwaitContext, true, p.parseOptionalBindingIdentifier)
+ case isGenerator:
+ name = doInContext(p, NodeFlagsYieldContext, true, p.parseOptionalBindingIdentifier)
+ case isAsync:
+ name = doInContext(p, NodeFlagsAwaitContext, true, p.parseOptionalBindingIdentifier)
+ default:
+ name = p.parseOptionalBindingIdentifier()
+ }
+ typeParameters := p.parseTypeParameters()
+ parameters := p.parseParameters(signatureFlags)
+ returnType := p.parseReturnType(SyntaxKindColonToken, false /*isType*/)
+ body := p.parseFunctionBlock(signatureFlags, nil /*diagnosticMessage*/)
+ p.contextFlags = saveContexFlags
+ result := p.factory.NewFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, returnType, body)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseOptionalBindingIdentifier() *Node {
+ if p.isBindingIdentifier() {
+ return p.parseBindingIdentifier()
+ }
+ return nil
+}
+
+func (p *Parser) parseDecoratedExpression() *Expression {
+ pos := p.nodePos()
+ hasJSDoc := p.hasPrecedingJSDocComment()
+ modifiers := p.parseModifiersWithOptions(true /*allowDecorators*/, false /*permitConstAsModifier*/, false /*stopOnStartOfClassStaticBlock*/)
+ if p.token == SyntaxKindClassKeyword {
+ return p.parseClassDeclarationOrExpression(pos, hasJSDoc, modifiers, SyntaxKindClassExpression)
+ }
+ p.parseErrorAt(p.nodePos(), p.nodePos(), diagnostics.Expression_expected)
+ result := p.factory.NewMissingDeclaration(modifiers)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseNewExpressionOrNewDotTarget() *Node {
+ pos := p.nodePos()
+ p.parseExpected(SyntaxKindNewKeyword)
+ if p.parseOptional(SyntaxKindDotToken) {
+ name := p.parseIdentifierName()
+ result := p.factory.NewMetaProperty(SyntaxKindNewKeyword, name)
+ p.finishNode(result, pos)
+ return result
+ }
+ expressionPos := p.nodePos()
+ expression := p.parseMemberExpressionRest(expressionPos, p.parsePrimaryExpression(), false /*allowOptionalChain*/)
+ var typeArguments *Node
+ // Absorb type arguments into NewExpression when preceding expression is ExpressionWithTypeArguments
+ if expression.kind == SyntaxKindExpressionWithTypeArguments {
+ typeArguments = expression.AsExpressionWithTypeArguments().typeArguments
+ expression = expression.AsExpressionWithTypeArguments().expression
+ }
+ if p.token == SyntaxKindQuestionDotToken {
+ p.parseErrorAtCurrentToken(diagnostics.Invalid_optional_chain_from_new_expression_Did_you_mean_to_call_0, getTextOfNodeFromSourceText(p.sourceText, expression))
+ }
+ var argumentList []*Expression
+ if p.token == SyntaxKindOpenParenToken {
+ argumentList = p.parseArgumentList()
+ }
+ result := p.factory.NewNewExpression(expression, typeArguments, argumentList)
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseKeywordExpression() *Node {
+ pos := p.nodePos()
+ result := p.factory.NewKeywordExpression(p.token)
+ p.nextToken()
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseLiteralExpression() *Node {
+ pos := p.nodePos()
+ text := p.scanner.TokenValue()
+ var result *Node
+ switch p.token {
+ case SyntaxKindStringLiteral:
+ result = p.factory.NewStringLiteral(text)
+ case SyntaxKindNumericLiteral:
+ result = p.factory.NewNumericLiteral(text)
+ case SyntaxKindBigintLiteral:
+ result = p.factory.NewBigintLiteral(text)
+ case SyntaxKindRegularExpressionLiteral:
+ result = p.factory.NewRegularExpressionLiteral(text)
+ case SyntaxKindNoSubstitutionTemplateLiteral:
+ result = p.factory.NewNoSubstitutionTemplateLiteral(text)
+ default:
+ panic("Unhandled case in parseLiteralExpression")
+ }
+ p.nextToken()
+ p.finishNode(result, pos)
+ return result
+}
+
+func (p *Parser) parseIdentifierNameErrorOnUnicodeEscapeSequence() *Node {
+ if p.scanner.HasUnicodeEscape() || p.scanner.HasExtendedUnicodeEscape() {
+ p.parseErrorAtCurrentToken(diagnostics.Unicode_escape_sequence_cannot_appear_here)
+ }
+ return p.createIdentifier(tokenIsIdentifierOrKeyword(p.token))
+}
+
+func (p *Parser) parseBindingIdentifier() *Node {
+ return p.parseBindingIdentifierWithDiagnostic(nil)
+}
+
+func (p *Parser) parseBindingIdentifierWithDiagnostic(privateIdentifierDiagnosticMessage *diagnostics.Message) *Node {
+ return p.createIdentifierWithDiagnostic(p.isBindingIdentifier(), nil /*diagnosticMessage*/, privateIdentifierDiagnosticMessage)
+}
+
+func (p *Parser) parseIdentifierName() *Node {
+ return p.parseIdentifierNameWithDiagnostic(nil)
+}
+
+func (p *Parser) parseIdentifierNameWithDiagnostic(diagnosticMessage *diagnostics.Message) *Node {
+ return p.createIdentifierWithDiagnostic(tokenIsIdentifierOrKeyword(p.token), diagnosticMessage, nil)
+}
+
+func (p *Parser) parseIdentifier() *Node {
+ return p.parseIdentifierWithDiagnostic(nil, nil)
+}
+
+func (p *Parser) parseIdentifierWithDiagnostic(diagnosticMessage *diagnostics.Message, privateIdentifierDiagnosticMessage *diagnostics.Message) *Node {
+ return p.createIdentifierWithDiagnostic(p.isIdentifier(), diagnosticMessage, privateIdentifierDiagnosticMessage)
+}
+
+func (p *Parser) createIdentifier(isIdentifier bool) *Node {
+ return p.createIdentifierWithDiagnostic(isIdentifier, nil, nil)
+}
+
+func (p *Parser) createIdentifierWithDiagnostic(isIdentifier bool, diagnosticMessage *diagnostics.Message, privateIdentifierDiagnosticMessage *diagnostics.Message) *Node {
+ if isIdentifier {
+ pos := p.nodePos()
+ text := p.scanner.TokenValue()
+ p.internIdentifier(text)
+ p.nextToken()
+ result := p.newIdentifier(text)
+ p.finishNode(result, pos)
+ return result
+ }
+ if p.token == SyntaxKindPrivateIdentifier {
+ if privateIdentifierDiagnosticMessage != nil {
+ p.parseErrorAtCurrentToken(privateIdentifierDiagnosticMessage)
+ } else {
+ p.parseErrorAtCurrentToken(diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies)
+ }
+ return p.createIdentifier(true /*isIdentifier*/)
+ }
+ if diagnosticMessage != nil {
+ p.parseErrorAtCurrentToken(diagnosticMessage)
+ } else if isReservedWord(p.token) {
+ p.parseErrorAtCurrentToken(diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, p.scanner.TokenText())
+ } else {
+ p.parseErrorAtCurrentToken(diagnostics.Identifier_expected)
+ }
+ result := p.newIdentifier("")
+ p.finishNode(result, p.nodePos())
+ return result
+}
+
+func (p *Parser) internIdentifier(text string) {
+ p.identifiers[text] = true
+}
+
+func (p *Parser) finishNode(node *Node, pos int) {
+ node.loc = NewTextRange(pos, p.nodePos())
+ node.flags |= p.contextFlags
+}
+
+func (p *Parser) nextTokenIsSlash() bool {
+ return p.nextToken() == SyntaxKindSlashToken
+}
+
+func (p *Parser) scanTypeMemberStart() bool {
+ // Return true if we have the start of a signature member
+ if p.token == SyntaxKindOpenParenToken || p.token == SyntaxKindLessThanToken || p.token == SyntaxKindGetKeyword || p.token == SyntaxKindSetKeyword {
+ return true
+ }
+ idToken := false
+ // Eat up all modifiers, but hold on to the last one in case it is actually an identifier
+ for isModifierKind(p.token) {
+ idToken = true
+ p.nextToken()
+ }
+ // Index signatures and computed property names are type members
+ if p.token == SyntaxKindOpenBracketToken {
+ return true
+ }
+ // Try to get the first property-like token following all modifiers
+ if p.isLiteralPropertyName() {
+ idToken = true
+ p.nextToken()
+ }
+ // If we were able to get any potential identifier, check that it is
+ // the start of a member declaration
+ if idToken {
+ return p.token == SyntaxKindOpenParenToken || p.token == SyntaxKindLessThanToken || p.token == SyntaxKindQuestionToken || p.token == SyntaxKindColonToken || p.token == SyntaxKindCommaToken || p.canParseSemicolon()
+ }
+ return false
+}
+
+func (p *Parser) scanClassMemberStart() bool {
+ idToken := SyntaxKindUnknown
+ if p.token == SyntaxKindAtToken {
+ return true
+ }
+ // Eat up all modifiers, but hold on to the last one in case it is actually an identifier.
+ for isModifierKind(p.token) {
+ idToken = p.token
+ // If the idToken is a class modifier (protected, private, public, and static), it is
+ // certain that we are starting to parse class member. This allows better error recovery
+ // Example:
+ // public foo() ... // true
+ // public @dec blah ... // true; we will then report an error later
+ // export public ... // true; we will then report an error later
+ if isClassMemberModifier(idToken) {
+ return true
+ }
+ p.nextToken()
+ }
+ if p.token == SyntaxKindAsteriskToken {
+ return true
+ }
+ // Try to get the first property-like token following all modifiers.
+ // This can either be an identifier or the 'get' or 'set' keywords.
+ if p.isLiteralPropertyName() {
+ idToken = p.token
+ p.nextToken()
+ }
+ // Index signatures and computed properties are class members; we can parse.
+ if p.token == SyntaxKindOpenBracketToken {
+ return true
+ }
+ // If we were able to get any potential identifier...
+ if idToken != SyntaxKindUnknown {
+ // If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse.
+ if !isKeyword(idToken) || idToken == SyntaxKindSetKeyword || idToken == SyntaxKindGetKeyword {
+ return true
+ }
+ // If it *is* a keyword, but not an accessor, check a little farther along
+ // to see if it should actually be parsed as a class member.
+ switch p.token {
+ case SyntaxKindOpenParenToken, // Method declaration
+ SyntaxKindLessThanToken, // Generic Method declaration
+ SyntaxKindExclamationToken, // Non-null assertion on property name
+ SyntaxKindColonToken, // Type Annotation for declaration
+ SyntaxKindEqualsToken, // Initializer for declaration
+ SyntaxKindQuestionToken: // Not valid, but permitted so that it gets caught later on.
+ return true
+ }
+ // Covers
+ // - Semicolons (declaration termination)
+ // - Closing braces (end-of-class, must be declaration)
+ // - End-of-files (not valid, but permitted so that it gets caught later on)
+ // - Line-breaks (enabling *automatic semicolon insertion*)
+ return p.canParseSemicolon()
+ }
+ return false
+}
+
+func (p *Parser) canParseSemicolon() bool {
+ // If there's a real semicolon, then we can always parse it out.
+ // We can parse out an optional semicolon in ASI cases in the following cases.
+ return p.token == SyntaxKindSemicolonToken || p.token == SyntaxKindCloseBraceToken || p.token == SyntaxKindEndOfFile || p.hasPrecedingLineBreak()
+}
+
+func (p *Parser) tryParseSemicolon() bool {
+ if !p.canParseSemicolon() {
+ return false
+ }
+ if p.token == SyntaxKindSemicolonToken {
+ // consume the semicolon if it was explicitly provided.
+ p.nextToken()
+ }
+ return true
+}
+
+func (p *Parser) parseSemicolon() bool {
+ return p.tryParseSemicolon() || p.parseExpected(SyntaxKindSemicolonToken)
+}
+
+func (p *Parser) isLiteralPropertyName() bool {
+ return tokenIsIdentifierOrKeyword(p.token) || p.token == SyntaxKindStringLiteral || p.token == SyntaxKindNumericLiteral || p.token == SyntaxKindBigintLiteral
+}
+
+func (p *Parser) isStartOfStatement() bool {
+ switch p.token {
+ // 'catch' and 'finally' do not actually indicate that the code is part of a statement,
+ // however, we say they are here so that we may gracefully parse them and error later.
+ case SyntaxKindAtToken, SyntaxKindSemicolonToken, SyntaxKindOpenBraceToken, SyntaxKindVarKeyword, SyntaxKindLetKeyword,
+ SyntaxKindUsingKeyword, SyntaxKindFunctionKeyword, SyntaxKindClassKeyword, SyntaxKindEnumKeyword, SyntaxKindIfKeyword,
+ SyntaxKindDoKeyword, SyntaxKindWhileKeyword, SyntaxKindForKeyword, SyntaxKindContinueKeyword, SyntaxKindBreakKeyword,
+ SyntaxKindReturnKeyword, SyntaxKindWithKeyword, SyntaxKindSwitchKeyword, SyntaxKindThrowKeyword, SyntaxKindTryKeyword,
+ SyntaxKindDebuggerKeyword, SyntaxKindCatchKeyword, SyntaxKindFinallyKeyword:
+ return true
+ case SyntaxKindImportKeyword:
+ return p.isStartOfDeclaration() || p.isNextTokenOpenParenOrLessThanOrDot()
+ case SyntaxKindConstKeyword, SyntaxKindExportKeyword:
+ return p.isStartOfDeclaration()
+ case SyntaxKindAsyncKeyword, SyntaxKindDeclareKeyword, SyntaxKindInterfaceKeyword, SyntaxKindModuleKeyword, SyntaxKindNamespaceKeyword,
+ SyntaxKindTypeKeyword, SyntaxKindGlobalKeyword:
+ // When these don't start a declaration, they're an identifier in an expression statement
+ return true
+ case SyntaxKindAccessorKeyword, SyntaxKindPublicKeyword, SyntaxKindPrivateKeyword, SyntaxKindProtectedKeyword, SyntaxKindStaticKeyword,
+ SyntaxKindReadonlyKeyword:
+ // When these don't start a declaration, they may be the start of a class member if an identifier
+ // immediately follows. Otherwise they're an identifier in an expression statement.
+ return p.isStartOfDeclaration() || !p.lookAhead(p.nextTokenIsIdentifierOrKeywordOnSameLine)
+
+ default:
+ return p.isStartOfExpression()
+ }
+}
+
+func (p *Parser) isStartOfDeclaration() bool {
+ return p.lookAhead(p.scanStartOfDeclaration)
+}
+
+func (p *Parser) scanStartOfDeclaration() bool {
+ for {
+ switch p.token {
+ case SyntaxKindVarKeyword, SyntaxKindLetKeyword, SyntaxKindConstKeyword, SyntaxKindFunctionKeyword, SyntaxKindClassKeyword,
+ SyntaxKindEnumKeyword:
+ return true
+ case SyntaxKindUsingKeyword:
+ return p.isUsingDeclaration()
+ case SyntaxKindAwaitKeyword:
+ return p.isAwaitUsingDeclaration()
+ // 'declare', 'module', 'namespace', 'interface'* and 'type' are all legal JavaScript identifiers;
+ // however, an identifier cannot be followed by another identifier on the same line. This is what we
+ // count on to parse out the respective declarations. For instance, we exploit this to say that
+ //
+ // namespace n
+ //
+ // can be none other than the beginning of a namespace declaration, but need to respect that JavaScript sees
+ //
+ // namespace
+ // n
+ //
+ // as the identifier 'namespace' on one line followed by the identifier 'n' on another.
+ // We need to look one token ahead to see if it permissible to try parsing a declaration.
+ //
+ // *Note*: 'interface' is actually a strict mode reserved word. So while
+ //
+ // "use strict"
+ // interface
+ // I {}
+ //
+ // could be legal, it would add complexity for very little gain.
+ case SyntaxKindInterfaceKeyword, SyntaxKindTypeKeyword:
+ return p.nextTokenIsIdentifierOnSameLine()
+ case SyntaxKindModuleKeyword, SyntaxKindNamespaceKeyword:
+ return p.nextTokenIsIdentifierOrStringLiteralOnSameLine()
+ case SyntaxKindAbstractKeyword, SyntaxKindAccessorKeyword, SyntaxKindAsyncKeyword, SyntaxKindDeclareKeyword, SyntaxKindPrivateKeyword,
+ SyntaxKindProtectedKeyword, SyntaxKindPublicKeyword, SyntaxKindReadonlyKeyword:
+ previousToken := p.token
+ p.nextToken()
+ // ASI takes effect for this modifier.
+ if p.hasPrecedingLineBreak() {
+ return false
+ }
+ if previousToken == SyntaxKindDeclareKeyword && p.token == SyntaxKindTypeKeyword {
+ // If we see 'declare type', then commit to parsing a type alias. parseTypeAliasDeclaration will
+ // report Line_break_not_permitted_here if needed.
+ return true
+ }
+ continue
+ case SyntaxKindGlobalKeyword:
+ p.nextToken()
+ return p.token == SyntaxKindOpenBraceToken || p.token == SyntaxKindIdentifier || p.token == SyntaxKindExportKeyword
+ case SyntaxKindImportKeyword:
+ p.nextToken()
+ return p.token == SyntaxKindStringLiteral || p.token == SyntaxKindAsteriskToken || p.token == SyntaxKindOpenBraceToken || tokenIsIdentifierOrKeyword(p.token)
+ case SyntaxKindExportKeyword:
+ p.nextToken()
+ if p.token == SyntaxKindEqualsToken || p.token == SyntaxKindAsteriskToken || p.token == SyntaxKindOpenBraceToken ||
+ p.token == SyntaxKindDefaultKeyword || p.token == SyntaxKindAsKeyword || p.token == SyntaxKindAtToken {
+ return true
+ }
+ if p.token == SyntaxKindTypeKeyword {
+ p.nextToken()
+ return p.token == SyntaxKindAsteriskToken || p.token == SyntaxKindOpenBraceToken || p.isIdentifier() && !p.hasPrecedingLineBreak()
+ }
+ continue
+ case SyntaxKindStaticKeyword:
+ p.nextToken()
+ continue
+ }
+ return false
+ }
+}
+
+func (p *Parser) isStartOfExpression() bool {
+ if p.isStartOfLeftHandSideExpression() {
+ return true
+ }
+ switch p.token {
+ case SyntaxKindPlusToken, SyntaxKindMinusToken, SyntaxKindTildeToken, SyntaxKindExclamationToken, SyntaxKindDeleteKeyword,
+ SyntaxKindTypeOfKeyword, SyntaxKindVoidKeyword, SyntaxKindPlusPlusToken, SyntaxKindMinusMinusToken, SyntaxKindLessThanToken,
+ SyntaxKindAwaitKeyword, SyntaxKindYieldKeyword, SyntaxKindPrivateIdentifier, SyntaxKindAtToken:
+ // Yield/await always starts an expression. Either it is an identifier (in which case
+ // it is definitely an expression). Or it's a keyword (either because we're in
+ // a generator or async function, or in strict mode (or both)) and it started a yield or await expression.
+ return true
+ }
+ // Error tolerance. If we see the start of some binary operator, we consider
+ // that the start of an expression. That way we'll parse out a missing identifier,
+ // give a good message about an identifier being missing, and then consume the
+ // rest of the binary expression.
+ if p.isBinaryOperator() {
+ return true
+ }
+ return p.isIdentifier()
+}
+
+func (p *Parser) isStartOfLeftHandSideExpression() bool {
+ switch p.token {
+ case SyntaxKindThisKeyword, SyntaxKindSuperKeyword, SyntaxKindNullKeyword, SyntaxKindTrueKeyword, SyntaxKindFalseKeyword,
+ SyntaxKindNumericLiteral, SyntaxKindBigintLiteral, SyntaxKindStringLiteral, SyntaxKindNoSubstitutionTemplateLiteral, SyntaxKindTemplateHead,
+ SyntaxKindOpenParenToken, SyntaxKindOpenBracketToken, SyntaxKindOpenBraceToken, SyntaxKindFunctionKeyword, SyntaxKindClassKeyword,
+ SyntaxKindNewKeyword, SyntaxKindSlashToken, SyntaxKindSlashEqualsToken, SyntaxKindIdentifier:
+ return true
+ case SyntaxKindImportKeyword:
+ return p.isNextTokenOpenParenOrLessThanOrDot()
+ }
+ return p.isIdentifier()
+}
+
+func (p *Parser) isStartOfType(inStartOfParameter bool) bool {
+ switch p.token {
+ case SyntaxKindAnyKeyword, SyntaxKindUnknownKeyword, SyntaxKindStringKeyword, SyntaxKindNumberKeyword, SyntaxKindBigIntKeyword,
+ SyntaxKindBooleanKeyword, SyntaxKindReadonlyKeyword, SyntaxKindSymbolKeyword, SyntaxKindUniqueKeyword, SyntaxKindVoidKeyword,
+ SyntaxKindUndefinedKeyword, SyntaxKindNullKeyword, SyntaxKindThisKeyword, SyntaxKindTypeOfKeyword, SyntaxKindNeverKeyword,
+ SyntaxKindOpenBraceToken, SyntaxKindOpenBracketToken, SyntaxKindLessThanToken, SyntaxKindBarToken, SyntaxKindAmpersandToken,
+ SyntaxKindNewKeyword, SyntaxKindStringLiteral, SyntaxKindNumericLiteral, SyntaxKindBigintLiteral, SyntaxKindTrueKeyword,
+ SyntaxKindFalseKeyword, SyntaxKindObjectKeyword, SyntaxKindAsteriskToken, SyntaxKindQuestionToken, SyntaxKindExclamationToken,
+ SyntaxKindDotDotDotToken, SyntaxKindInferKeyword, SyntaxKindImportKeyword, SyntaxKindAssertsKeyword, SyntaxKindNoSubstitutionTemplateLiteral,
+ SyntaxKindTemplateHead:
+ return true
+ case SyntaxKindFunctionKeyword:
+ return !inStartOfParameter
+ case SyntaxKindMinusToken:
+ return !inStartOfParameter && p.lookAhead(p.nextTokenIsNumericOrBigIntLiteral)
+ case SyntaxKindOpenParenToken:
+ // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier,
+ // or something that starts a type. We don't want to consider things like '(1)' a type.
+ return !inStartOfParameter && p.lookAhead(p.nextIsParenthesizedOrFunctionType)
+ }
+ return p.isIdentifier()
+}
+
+func (p *Parser) nextTokenIsNumericOrBigIntLiteral() bool {
+ p.nextToken()
+ return p.token == SyntaxKindNumericLiteral || p.token == SyntaxKindBigintLiteral
+}
+
+func (p *Parser) nextIsParenthesizedOrFunctionType() bool {
+ p.nextToken()
+ return p.token == SyntaxKindCloseParenToken || p.isStartOfParameter(false /*isJSDocParameter*/) || p.isStartOfType(false /*inStartOfParameter*/)
+}
+
+func (p *Parser) isStartOfParameter(isJSDocParameter bool) bool {
+ return p.token == SyntaxKindDotDotDotToken ||
+ p.isBindingIdentifierOrPrivateIdentifierOrPattern() ||
+ isModifierKind(p.token) ||
+ p.token == SyntaxKindAtToken ||
+ p.isStartOfType(!isJSDocParameter /*inStartOfParameter*/)
+}
+
+func (p *Parser) isBindingIdentifierOrPrivateIdentifierOrPattern() bool {
+ return p.token == SyntaxKindOpenBraceToken || p.token == SyntaxKindOpenBracketToken || p.token == SyntaxKindPrivateIdentifier || p.isBindingIdentifier()
+}
+
+func (p *Parser) isNextTokenOpenParenOrLessThanOrDot() bool {
+ return p.lookAhead(p.nextTokenIsOpenParenOrLessThanOrDot)
+}
+
+func (p *Parser) nextTokenIsOpenParenOrLessThanOrDot() bool {
+ switch p.nextToken() {
+ case SyntaxKindOpenParenToken, SyntaxKindLessThanToken, SyntaxKindDotToken:
+ return true
+ }
+ return false
+}
+
+func (p *Parser) nextTokenIsIdentifierOnSameLine() bool {
+ p.nextToken()
+ return p.isIdentifier() && !p.hasPrecedingLineBreak()
+}
+
+func (p *Parser) nextTokenIsIdentifierOrStringLiteralOnSameLine() bool {
+ p.nextToken()
+ return (p.isIdentifier() || p.token == SyntaxKindStringLiteral) && !p.hasPrecedingLineBreak()
+}
+
+// Ignore strict mode flag because we will report an error in type checker instead.
+func (p *Parser) isIdentifier() bool {
+ if p.token == SyntaxKindIdentifier {
+ return true
+ }
+ // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is
+ // considered a keyword and is not an identifier.
+ // If we have a 'await' keyword, and we're in the [Await] context, then 'await' is
+ // considered a keyword and is not an identifier.
+ if p.token == SyntaxKindYieldKeyword && p.inYieldContext() || p.token == SyntaxKindAwaitKeyword && p.inAwaitContext() {
+ return false
+ }
+ return p.token > SyntaxKindLastReservedWord
+}
+
+func (p *Parser) isBindingIdentifier() bool {
+ // `let await`/`let yield` in [Yield] or [Await] are allowed here and disallowed in the binder.
+ return p.token == SyntaxKindIdentifier || p.token > SyntaxKindLastReservedWord
+}
+
+func (p *Parser) isImportAttributeName() bool {
+ return tokenIsIdentifierOrKeyword(p.token) || p.token == SyntaxKindStringLiteral
+}
+
+func (p *Parser) isBinaryOperator() bool {
+ if p.inDisallowInContext() && p.token == SyntaxKindInKeyword {
+ return false
+ }
+ return getBinaryOperatorPrecedence(p.token) != OperatorPrecedenceInvalid
+}
+
+func (p *Parser) isValidHeritageClauseObjectLiteral() bool {
+ return p.lookAhead(p.nextIsValidHeritageClauseObjectLiteral)
+}
+
+func (p *Parser) nextIsValidHeritageClauseObjectLiteral() bool {
+ if p.nextToken() == SyntaxKindCloseBraceToken {
+ // if we see "extends {}" then only treat the {} as what we're extending (and not
+ // the class body) if we have:
+ //
+ // extends {} {
+ // extends {},
+ // extends {} extends
+ // extends {} implements
+ next := p.nextToken()
+ return next == SyntaxKindCommaToken || next == SyntaxKindOpenBraceToken || next == SyntaxKindExtendsKeyword || next == SyntaxKindImplementsKeyword
+ }
+ return true
+}
+
+func (p *Parser) isHeritageClause() bool {
+ return p.token == SyntaxKindExtendsKeyword || p.token == SyntaxKindImplementsKeyword
+}
+
+func (p *Parser) isHeritageClauseExtendsOrImplementsKeyword() bool {
+ return p.isHeritageClause() && p.lookAhead(p.nextIsStartOfExpression)
+}
+
+func (p *Parser) nextIsStartOfExpression() bool {
+ p.nextToken()
+ return p.isStartOfExpression()
+}
+
+func (p *Parser) isUsingDeclaration() bool {
+ // 'using' always starts a lexical declaration if followed by an identifier. We also eagerly parse
+ // |ObjectBindingPattern| so that we can report a grammar error during check. We don't parse out
+ // |ArrayBindingPattern| since it potentially conflicts with element access (i.e., `using[x]`).
+ return p.lookAhead(p.nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLine)
+}
+
+func (p *Parser) nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLine() bool {
+ p.nextToken()
+ return p.isBindingIdentifier() || p.token == SyntaxKindOpenBraceToken && !p.hasPrecedingLineBreak()
+}
+
+func (p *Parser) nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLineDisallowOf() bool {
+ return p.nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLine() && p.token != SyntaxKindOfKeyword
+}
+
+func (p *Parser) isAwaitUsingDeclaration() bool {
+ return p.lookAhead(p.nextIsUsingKeywordThenBindingIdentifierOrStartOfObjectDestructuringOnSameLine)
+}
+
+func (p *Parser) nextIsUsingKeywordThenBindingIdentifierOrStartOfObjectDestructuringOnSameLine() bool {
+ return p.nextToken() == SyntaxKindUsingKeyword && p.nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLine()
+}
+
+func (p *Parser) nextTokenIsTokenStringLiteral() bool {
+ return p.nextToken() == SyntaxKindStringLiteral
+}
+
+func (p *Parser) setContextFlags(flags NodeFlags, value bool) {
+ if value {
+ p.contextFlags |= flags
+ } else {
+ p.contextFlags &= ^flags
+ }
+}
+
+func doInContext[T any](p *Parser, flags NodeFlags, value bool, f func() T) T {
+ saveContextFlags := p.contextFlags
+ p.setContextFlags(flags, value)
+ result := f()
+ p.contextFlags = saveContextFlags
+ return result
+}
+
+func (p *Parser) inYieldContext() bool {
+ return p.contextFlags&NodeFlagsYieldContext != 0
+}
+
+func (p *Parser) inDisallowInContext() bool {
+ return p.contextFlags&NodeFlagsDisallowInContext != 0
+}
+
+func (p *Parser) inDisallowConditionalTypesContext() bool {
+ return p.contextFlags&NodeFlagsDisallowConditionalTypesContext != 0
+}
+
+func (p *Parser) inDecoratorContext() bool {
+ return p.contextFlags&NodeFlagsDecoratorContext != 0
+}
+
+func (p *Parser) inAwaitContext() bool {
+ return p.contextFlags&NodeFlagsAwaitContext != 0
+}
+
+func (p *Parser) skipRangeTrivia(textRange TextRange) TextRange {
+ return NewTextRange(skipTrivia(p.sourceText, textRange.Pos()), textRange.End())
+}
+
+func isModifierKind(token SyntaxKind) bool {
+ switch token {
+ case SyntaxKindAbstractKeyword, SyntaxKindAccessorKeyword, SyntaxKindAsyncKeyword, SyntaxKindConstKeyword, SyntaxKindDeclareKeyword,
+ SyntaxKindDefaultKeyword, SyntaxKindExportKeyword, SyntaxKindImmediateKeyword, SyntaxKindInKeyword, SyntaxKindPublicKeyword,
+ SyntaxKindPrivateKeyword, SyntaxKindProtectedKeyword, SyntaxKindReadonlyKeyword, SyntaxKindStaticKeyword, SyntaxKindOutKeyword,
+ SyntaxKindOverrideKeyword:
+ return true
+ }
+ return false
+}
+
+func isClassMemberModifier(token SyntaxKind) bool {
+ return isParameterPropertyModifier(token) || token == SyntaxKindStaticKeyword || token == SyntaxKindOverrideKeyword || token == SyntaxKindAccessorKeyword
+}
+
+func isParameterPropertyModifier(kind SyntaxKind) bool {
+ return modifierToFlag(kind)&ModifierFlagsParameterPropertyModifier != 0
+}
+
+func isKeyword(token SyntaxKind) bool {
+ return SyntaxKindFirstKeyword <= token && token <= SyntaxKindLastKeyword
+}
+
+func isReservedWord(token SyntaxKind) bool {
+ return SyntaxKindFirstReservedWord <= token && token <= SyntaxKindLastReservedWord
+}
+
+func isFileProbablyExternalModule(sourceFile *SourceFile) *Node {
+ for _, statement := range sourceFile.statements {
+ if isAnExternalModuleIndicatorNode(statement) {
+ return statement
+ }
+ }
+ return getImportMetaIfNecessary(sourceFile)
+}
+
+func isAnExternalModuleIndicatorNode(node *Statement) bool {
+ return hasSyntacticModifier(node, ModifierFlagsExport) ||
+ isImportEqualsDeclaration(node) && isExternalModuleReference(node.AsImportEqualsDeclaration().moduleReference) ||
+ isImportDeclaration(node) || isExportAssignment(node) || isExportDeclaration(node)
+}
+
+func getImportMetaIfNecessary(sourceFile *SourceFile) *Node {
+ if sourceFile.AsNode().flags&NodeFlagsPossiblyContainsImportMeta != 0 {
+ return findChildNode(sourceFile.AsNode(), isImportMeta)
+ }
+ return nil
+}
+
+func findChildNode(root *Node, check func(*Node) bool) *Node {
+ var result *Node
+ var visit func(*Node) bool
+ visit = func(node *Node) bool {
+ if check(node) {
+ result = node
+ return true
+ }
+ return node.ForEachChild(visit)
+ }
+ visit(root)
+ return result
+}
+
+func tagNamesAreEquivalent(lhs *Expression, rhs *Expression) bool {
+ if lhs.kind != rhs.kind {
+ return false
+ }
+ switch lhs.kind {
+ case SyntaxKindIdentifier:
+ return lhs.AsIdentifier().text == rhs.AsIdentifier().text
+ case SyntaxKindThisKeyword:
+ return true
+ case SyntaxKindJsxNamespacedName:
+ return lhs.AsJsxNamespacedName().namespace.AsIdentifier().text == rhs.AsJsxNamespacedName().namespace.AsIdentifier().text &&
+ lhs.AsJsxNamespacedName().name.AsIdentifier().text == rhs.AsJsxNamespacedName().name.AsIdentifier().text
+ case SyntaxKindPropertyAccessExpression:
+ return getTextOfIdentifierOrLiteral(lhs.AsPropertyAccessExpression().name) == getTextOfIdentifierOrLiteral(rhs.AsPropertyAccessExpression().name) &&
+ tagNamesAreEquivalent(lhs.AsPropertyAccessExpression().expression, rhs.AsPropertyAccessExpression().expression)
+ }
+ panic("Unhandled case in tagNamesAreEquivalent")
+}
+
+func attachFileToDiagnostics(diagnostics []*Diagnostic, file *SourceFile) []*Diagnostic {
+ for _, d := range diagnostics {
+ d.file = file
+ }
+ return diagnostics
+}
+
+func isDeclarationFileName(fileName string) bool {
+ return getDeclarationFileExtension(fileName) != ""
+}
+
+func getDeclarationFileExtension(fileName string) string {
+ _, base := path.Split(fileName)
+ for _, ext := range supportedDeclarationExtensions {
+ if strings.HasSuffix(base, ext) {
+ return ext
+ }
+ }
+ if strings.HasSuffix(base, ExtensionTs) {
+ index := strings.Index(base, ".d.")
+ if index >= 0 {
+ return base[index:]
+ }
+ }
+ return ""
+}
diff --git a/internal/compiler/parser_test.go b/internal/compiler/parser_test.go
new file mode 100644
index 0000000000..14c68b1dfa
--- /dev/null
+++ b/internal/compiler/parser_test.go
@@ -0,0 +1,20 @@
+package compiler
+
+import (
+ "fmt"
+ "os"
+ "testing"
+)
+
+func BenchmarkParse(b *testing.B) {
+ fileName := "../../_submodules/TypeScript/src/compiler/checker.ts"
+ bytes, err := os.ReadFile(fileName)
+ if err != nil {
+ fmt.Println(err)
+ }
+ sourceText := string(bytes)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ParseSourceFile(fileName, sourceText, ScriptTargetESNext)
+ }
+}
diff --git a/internal/compiler/pkg.go b/internal/compiler/pkg.go
index 039ff2b0c4..aa86763b4c 100644
--- a/internal/compiler/pkg.go
+++ b/internal/compiler/pkg.go
@@ -1,4 +1,2 @@
// Package compiler implements the TypeScript compiler.
package compiler
-
-func CreateSourceFile() {}
diff --git a/internal/compiler/printer.go b/internal/compiler/printer.go
new file mode 100644
index 0000000000..6783a16739
--- /dev/null
+++ b/internal/compiler/printer.go
@@ -0,0 +1,116 @@
+package compiler
+
+import (
+ "strconv"
+ "strings"
+)
+
+func (c *Checker) symbolToString(s *Symbol) string {
+ return s.name // !!!
+}
+
+func (c *Checker) typeToString(t *Type) string {
+ p := c.newPrinter()
+ p.printType(t)
+ return p.string()
+}
+
+type Printer struct {
+ c *Checker
+ sb strings.Builder
+ depth int
+}
+
+func (c *Checker) newPrinter() *Printer {
+ return &Printer{c: c}
+}
+
+func (p *Printer) string() string {
+ return p.sb.String()
+}
+
+func (p *Printer) print(s string) {
+ p.sb.WriteString(s)
+}
+
+func (p *Printer) printType(t *Type) {
+ switch {
+ case t.flags&TypeFlagsIntrinsic != 0:
+ p.print(t.IntrinsicType().intrinsicName)
+ case t.flags&TypeFlagsLiteral != 0:
+ p.printLiteralType(t)
+ case t.flags&TypeFlagsObject != 0:
+ p.printObjectType(t)
+ }
+}
+
+func (p *Printer) printLiteralType(t *Type) {
+ if t.flags&TypeFlagsEnumLiteral != 0 {
+ p.printEnumLiteral(t)
+ } else {
+ switch value := t.LiteralType().value.(type) {
+ case string:
+ p.printStringLiteral(value)
+ case float64:
+ p.printNumberLiteral(value)
+ case bool:
+ p.printBooleanLiteral(value)
+ case PseudoBigint:
+ p.printBigintLiteral(value)
+ }
+ }
+}
+
+func (p *Printer) printStringLiteral(s string) {
+ p.print("\"")
+ p.print(s)
+ p.print("\"")
+}
+
+func (p *Printer) printNumberLiteral(f float64) {
+ p.print(strconv.FormatFloat(f, 'g', -1, 64))
+}
+
+func (p *Printer) printBooleanLiteral(b bool) {
+ p.print(ifElse(b, "true", "false"))
+}
+
+func (p *Printer) printBigintLiteral(b PseudoBigint) {
+ if b.negative {
+ p.print("-")
+ }
+ p.print(b.base10Value)
+}
+
+func (p *Printer) printEnumLiteral(t *Type) {
+ p.print(p.c.getParentOfSymbol(t.symbol).name)
+ p.print(".")
+ p.print(t.symbol.name)
+}
+
+func (p *Printer) printObjectType(t *Type) {
+ if p.depth != 0 {
+ p.print("???")
+ return
+ }
+ p.depth++
+ props := p.c.getPropertiesOfObjectType(t)
+ sortSymbols(props)
+ p.print("{")
+ var tail bool
+ for _, prop := range props {
+ if tail {
+ p.print(",")
+ }
+ p.print(" ")
+ p.print(prop.name)
+ p.print(": ")
+ p.printType(p.c.getTypeOfSymbol(prop))
+ tail = true
+ }
+ if tail {
+ p.print(" ")
+ }
+ p.print("}")
+ p.depth--
+}
diff --git a/internal/compiler/program.go b/internal/compiler/program.go
new file mode 100644
index 0000000000..f5380a5551
--- /dev/null
+++ b/internal/compiler/program.go
@@ -0,0 +1,375 @@
+package compiler
+
+import (
+ "encoding/json"
+ "path/filepath"
+ "slices"
+ "strings"
+)
+
+type ProgramOptions struct {
+ RootPath string
+ Host CompilerHost
+ Options *CompilerOptions
+ SingleThreaded bool
+}
+
+type Program struct {
+ host CompilerHost
+ options *CompilerOptions
+ rootPath string
+ files []*SourceFile
+ filesByPath map[string]*SourceFile
+ nodeModules map[string]*SourceFile
+ checker *Checker
+ usesUriStyleNodeCoreModules Tristate
+ currentNodeModulesDepth int
+}
+
+var extensions = []string{".ts", ".tsx"}
+
+func NewProgram(options ProgramOptions) *Program {
+ p := &Program{}
+ p.options = options.Options
+ if p.options == nil {
+ p.options = &CompilerOptions{}
+ }
+ p.host = options.Host
+ if p.host == nil {
+ p.host = NewCompilerHost(p.options, options.SingleThreaded)
+ }
+ rootPath := options.RootPath
+ if rootPath == "" {
+ rootPath = "."
+ }
+ p.rootPath = p.host.AbsFileName(rootPath)
+ fileInfos := p.host.ReadDirectory(rootPath, extensions)
+ // Sort files by descending file size
+ slices.SortFunc(fileInfos, func(a FileInfo, b FileInfo) int {
+ return int(b.Size) - int(a.Size)
+ })
+ p.parseSourceFiles(fileInfos)
+ return p
+}
+
+func (p *Program) SourceFiles() []*SourceFile { return p.files }
+func (p *Program) Options() *CompilerOptions { return p.options }
+func (p *Program) Host() CompilerHost { return p.host }
+
+func (p *Program) parseSourceFiles(fileInfos []FileInfo) {
+ p.files = make([]*SourceFile, len(fileInfos))[:len(fileInfos)]
+ for i := range fileInfos {
+ p.host.RunTask(func() {
+ fileName := fileInfos[i].Name
+ text, _ := p.host.ReadFile(fileName)
+ sourceFile := ParseSourceFile(fileName, text, getEmitScriptTarget(p.options))
+ sourceFile.path, _ = filepath.Abs(fileName)
+ p.collectExternalModuleReferences(sourceFile)
+ p.files[i] = sourceFile
+ })
+ }
+ p.host.WaitForTasks()
+ p.filesByPath = make(map[string]*SourceFile)
+ for _, file := range p.files {
+ p.filesByPath[file.path] = file
+ }
+}
+
+func (p *Program) bindSourceFiles() {
+ for _, file := range p.files {
+ if !file.isBound {
+ p.host.RunTask(func() {
+ bindSourceFile(file, p.options)
+ })
+ }
+ }
+ p.host.WaitForTasks()
+}
+
+func (p *Program) getResolvedModule(currentSourceFile *SourceFile, moduleReference string) *SourceFile {
+ directory := filepath.Dir(currentSourceFile.path)
+ if isExternalModuleNameRelative(moduleReference) {
+ return p.findSourceFile(filepath.Join(directory, moduleReference))
+ }
+ return p.findNodeModule(moduleReference)
+}
+
+func (p *Program) findSourceFile(candidate string) *SourceFile {
+ extensionless := removeFileExtension(candidate)
+ for _, ext := range []string{ExtensionTs, ExtensionTsx, ExtensionDts} {
+ path := extensionless + ext
+ if result, ok := p.filesByPath[path]; ok {
+ return result
+ }
+ }
+ return nil
+}
+
+func (p *Program) findNodeModule(moduleReference string) *SourceFile {
+ if p.nodeModules == nil {
+ p.nodeModules = make(map[string]*SourceFile)
+ }
+ if sourceFile, ok := p.nodeModules[moduleReference]; ok {
+ return sourceFile
+ }
+ sourceFile := p.tryLoadNodeModule(filepath.Join(p.rootPath, "node_modules", moduleReference))
+ if sourceFile == nil {
+ sourceFile = p.tryLoadNodeModule(filepath.Join(p.rootPath, "node_modules/@types", moduleReference))
+ }
+ p.nodeModules[moduleReference] = sourceFile
+ return sourceFile
+}
+
+func (p *Program) tryLoadNodeModule(modulePath string) *SourceFile {
+ if packageJson, ok := p.host.ReadFile(filepath.Join(modulePath, "package.json")); ok {
+ var jsonMap map[string]any
+ if json.Unmarshal([]byte(packageJson), &jsonMap) == nil {
+ typesValue := jsonMap["types"]
+ if typesValue == nil {
+ typesValue = jsonMap["typings"]
+ }
+ if fileName, ok := typesValue.(string); ok {
+ path := filepath.Join(modulePath, fileName)
+ return p.filesByPath[path]
+ }
+ }
+ }
+ return nil
+}
+
+func (p *Program) GetSyntacticDiagnostics(sourceFile *SourceFile) []*Diagnostic {
+ return p.getDiagnosticsHelper(sourceFile, p.getSyntaticDiagnosticsForFile)
+}
+
+func (p *Program) GetBindDiagnostics(sourceFile *SourceFile) []*Diagnostic {
+ p.bindSourceFiles()
+ return p.getDiagnosticsHelper(sourceFile, p.getBindDiagnosticsForFile)
+}
+
+func (p *Program) GetSemanticDiagnostics(sourceFile *SourceFile) []*Diagnostic {
+ return p.getDiagnosticsHelper(sourceFile, p.getSemanticDiagnosticsForFile)
+}
+
+func (p *Program) GetGlobalDiagnostics() []*Diagnostic {
+ return sortAndDeduplicateDiagnostics(p.getTypeChecker().GetGlobalDiagnostics())
+}
+
+func (p *Program) getTypeChecker() *Checker {
+ if p.checker == nil {
+ p.checker = NewChecker(p)
+ }
+ return p.checker
+}
+
+func (p *Program) getSyntaticDiagnosticsForFile(sourceFile *SourceFile) []*Diagnostic {
+ return sourceFile.diagnostics
+}
+
+func (p *Program) getBindDiagnosticsForFile(sourceFile *SourceFile) []*Diagnostic {
+ return sourceFile.bindDiagnostics
+}
+
+func (p *Program) getSemanticDiagnosticsForFile(sourceFile *SourceFile) []*Diagnostic {
+ return p.getTypeChecker().GetDiagnostics(sourceFile)
+}
+
+func (p *Program) getDiagnosticsHelper(sourceFile *SourceFile, getDiagnostics func(*SourceFile) []*Diagnostic) []*Diagnostic {
+ if sourceFile != nil {
+ return sortAndDeduplicateDiagnostics(getDiagnostics(sourceFile))
+ }
+ var result []*Diagnostic
+ for _, file := range p.files {
+ result = append(result, getDiagnostics(file)...)
+ }
+ return sortAndDeduplicateDiagnostics(result)
+}
+
+func (p *Program) collectExternalModuleReferences(file *SourceFile) {
+ if file.moduleReferencesProcessed {
+ return
+ }
+ file.moduleReferencesProcessed = true
+ // !!!
+ // If we are importing helpers, we need to add a synthetic reference to resolve the
+ // helpers library. (A JavaScript file without `externalModuleIndicator` set might be
+ // a CommonJS module; `commonJsModuleIndicator` doesn't get set until the binder has
+ // run. We synthesize a helpers import for it just in case; it will never be used if
+ // the binder doesn't find and set a `commonJsModuleIndicator`.)
+ // if (isJavaScriptFile || (!file.isDeclarationFile && (getIsolatedModules(options) || isExternalModule(file)))) {
+ // if (options.importHelpers) {
+ // // synthesize 'import "tslib"' declaration
+ // imports = [createSyntheticImport(externalHelpersModuleNameText, file)];
+ // }
+ // const jsxImport = getJSXRuntimeImport(getJSXImplicitImportBase(options, file), options);
+ // if (jsxImport) {
+ // // synthesize `import "base/jsx-runtime"` declaration
+ // (imports ||= []).push(createSyntheticImport(jsxImport, file));
+ // }
+ // }
+ for _, node := range file.statements {
+ p.collectModuleReferences(file, node, false /*inAmbientModule*/)
+ }
+ // if ((file.flags & NodeFlags.PossiblyContainsDynamicImport) || isJavaScriptFile) {
+ // collectDynamicImportOrRequireOrJsDocImportCalls(file);
+ // }
+ // function collectDynamicImportOrRequireOrJsDocImportCalls(file: SourceFile) {
+ // const r = /import|require/g;
+ // while (r.exec(file.text) !== null) { // eslint-disable-line no-restricted-syntax
+ // const node = getNodeAtPosition(file, r.lastIndex);
+ // if (isJavaScriptFile && isRequireCall(node, /*requireStringLiteralLikeArgument*/ true)) {
+ // setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
+ // imports = append(imports, node.arguments[0]);
+ // }
+ // // we have to check the argument list has length of at least 1. We will still have to process these even though we have parsing error.
+ // else if (isImportCall(node) && node.arguments.length >= 1 && isStringLiteralLike(node.arguments[0])) {
+ // setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
+ // imports = append(imports, node.arguments[0]);
+ // }
+ // else if (isLiteralImportTypeNode(node)) {
+ // setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
+ // imports = append(imports, node.argument.literal);
+ // }
+ // else if (isJavaScriptFile && isJSDocImportTag(node)) {
+ // const moduleNameExpr = getExternalModuleName(node);
+ // if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text) {
+ // setParentRecursive(node, /*incremental*/ false);
+ // imports = append(imports, moduleNameExpr);
+ // }
+ // }
+ // }
+ // }
+ // /** Returns a token if position is in [start-of-leading-trivia, end), includes JSDoc only in JS files */
+ // function getNodeAtPosition(sourceFile: SourceFile, position: number): Node {
+ // let current: Node = sourceFile;
+ // const getContainingChild = (child: Node) => {
+ // if (child.pos <= position && (position < child.end || (position === child.end && (child.kind === SyntaxKind.EndOfFileToken)))) {
+ // return child;
+ // }
+ // };
+ // while (true) {
+ // const child = isJavaScriptFile && hasJSDocNodes(current) && forEach(current.jsDoc, getContainingChild) || forEachChild(current, getContainingChild);
+ // if (!child) {
+ // return current;
+ // }
+ // current = child;
+ // }
+ // }
+}
+
+var unprefixedNodeCoreModules = map[string]bool{
+ "assert": true,
+ "assert/strict": true,
+ "async_hooks": true,
+ "buffer": true,
+ "child_process": true,
+ "cluster": true,
+ "console": true,
+ "constants": true,
+ "crypto": true,
+ "dgram": true,
+ "diagnostics_channel": true,
+ "dns": true,
+ "dns/promises": true,
+ "domain": true,
+ "events": true,
+ "fs": true,
+ "fs/promises": true,
+ "http": true,
+ "http2": true,
+ "https": true,
+ "inspector": true,
+ "inspector/promises": true,
+ "module": true,
+ "net": true,
+ "os": true,
+ "path": true,
+ "path/posix": true,
+ "path/win32": true,
+ "perf_hooks": true,
+ "process": true,
+ "punycode": true,
+ "querystring": true,
+ "readline": true,
+ "readline/promises": true,
+ "repl": true,
+ "stream": true,
+ "stream/consumers": true,
+ "stream/promises": true,
+ "stream/web": true,
+ "string_decoder": true,
+ "sys": true,
+ "test/mock_loader": true,
+ "timers": true,
+ "timers/promises": true,
+ "tls": true,
+ "trace_events": true,
+ "tty": true,
+ "url": true,
+ "util": true,
+ "util/types": true,
+ "v8": true,
+ "vm": true,
+ "wasi": true,
+ "worker_threads": true,
+ "zlib": true,
+}
+
+var exclusivelyPrefixedNodeCoreModules = map[string]bool{
+ "node:sea": true,
+ "node:sqlite": true,
+ "node:test": true,
+ "node:test/reporters": true,
+}
+
+func (p *Program) collectModuleReferences(file *SourceFile, node *Statement, inAmbientModule bool) {
+ if isAnyImportOrReExport(node) {
+ moduleNameExpr := getExternalModuleName(node)
+ // TypeScript 1.0 spec (April 2014): 12.1.6
+ // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules
+ // only through top - level external module names. Relative external module names are not permitted.
+ if moduleNameExpr != nil && isStringLiteral(moduleNameExpr) {
+ moduleName := moduleNameExpr.AsStringLiteral().text
+ if moduleName != "" && (!inAmbientModule || !isExternalModuleNameRelative(moduleName)) {
+ setParentInChildren(node) // we need parent data on imports before the program is fully bound, so we ensure it's set here
+ file.imports = append(file.imports, moduleNameExpr)
+ if file.usesUriStyleNodeCoreModules != TSTrue && p.currentNodeModulesDepth == 0 && !file.isDeclarationFile {
+ if strings.HasPrefix(moduleName, "node:") && !exclusivelyPrefixedNodeCoreModules[moduleName] {
+ // Presence of `node:` prefix takes precedence over unprefixed node core modules
+ file.usesUriStyleNodeCoreModules = TSTrue
+ } else if file.usesUriStyleNodeCoreModules == TSUnknown && unprefixedNodeCoreModules[moduleName] {
+ // Avoid `unprefixedNodeCoreModules.has` for every import
+ file.usesUriStyleNodeCoreModules = TSFalse
+ }
+ }
+ }
+ }
+ return
+ }
+ if isModuleDeclaration(node) && isAmbientModule(node) && (inAmbientModule || hasSyntacticModifier(node, ModifierFlagsAmbient) || file.isDeclarationFile) {
+ setParentInChildren(node)
+ nameText := getTextOfIdentifierOrLiteral(node.AsModuleDeclaration().name)
+ // Ambient module declarations can be interpreted as augmentations for some existing external modules.
+ // This will happen in two cases:
+ // - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope
+ // - if current file is not external module then module augmentation is an ambient module declaration with non-relative module name
+ // immediately nested in top level ambient module declaration .
+ if isExternalModule(file) || (inAmbientModule && !isExternalModuleNameRelative(nameText)) {
+ file.moduleAugmentations = append(file.moduleAugmentations, node.AsModuleDeclaration().name)
+ } else if !inAmbientModule {
+ if file.isDeclarationFile {
+ // for global .d.ts files record name of ambient module
+ file.ambientModuleNames = append(file.ambientModuleNames, nameText)
+ }
+ // An AmbientExternalModuleDeclaration declares an external module.
+ // This type of declaration is permitted only in the global module.
+ // The StringLiteral must specify a top - level external module name.
+ // Relative external module names are not permitted
+ // NOTE: body of ambient module is always a module block, if it exists
+ if node.AsModuleDeclaration().body != nil {
+ for _, statement := range node.AsModuleDeclaration().body.AsModuleBlock().statements {
+ p.collectModuleReferences(file, statement, true /*inAmbientModule*/)
+ }
+ }
+ }
+ }
+}
diff --git a/internal/compiler/scanner.go b/internal/compiler/scanner.go
new file mode 100644
index 0000000000..4effb8240a
--- /dev/null
+++ b/internal/compiler/scanner.go
@@ -0,0 +1,1740 @@
+package compiler
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "unicode/utf8"
+
+ "github.com/microsoft/typescript-go/internal/compiler/diagnostics"
+)
+
+type TokenFlags int32
+
+const (
+ TokenFlagsNone TokenFlags = 0
+ TokenFlagsPrecedingLineBreak TokenFlags = 1 << 0
+ TokenFlagsPrecedingJSDocComment TokenFlags = 1 << 1
+ TokenFlagsUnterminated TokenFlags = 1 << 2
+ TokenFlagsExtendedUnicodeEscape TokenFlags = 1 << 3 // e.g. `\u{10ffff}`
+ TokenFlagsScientific TokenFlags = 1 << 4 // e.g. `10e2`
+ TokenFlagsOctal TokenFlags = 1 << 5 // e.g. `0777`
+ TokenFlagsHexSpecifier TokenFlags = 1 << 6 // e.g. `0x00000000`
+ TokenFlagsBinarySpecifier TokenFlags = 1 << 7 // e.g. `0b0110010000000000`
+ TokenFlagsOctalSpecifier TokenFlags = 1 << 8 // e.g. `0o777`
+ TokenFlagsContainsSeparator TokenFlags = 1 << 9 // e.g. `0b1100_0101`
+ TokenFlagsUnicodeEscape TokenFlags = 1 << 10 // e.g. `\u00a0`
+ TokenFlagsContainsInvalidEscape TokenFlags = 1 << 11 // e.g. `\uhello`
+ TokenFlagsHexEscape TokenFlags = 1 << 12 // e.g. `\xa0`
+ TokenFlagsContainsLeadingZero TokenFlags = 1 << 13 // e.g. `0888`
+ TokenFlagsContainsInvalidSeparator TokenFlags = 1 << 14 // e.g. `0_1`
+ TokenFlagsPrecedingJSDocLeadingAsterisks TokenFlags = 1 << 15
+ TokenFlagsBinaryOrOctalSpecifier TokenFlags = TokenFlagsBinarySpecifier | TokenFlagsOctalSpecifier
+ TokenFlagsWithSpecifier TokenFlags = TokenFlagsHexSpecifier | TokenFlagsBinaryOrOctalSpecifier
+ TokenFlagsStringLiteralFlags TokenFlags = TokenFlagsHexEscape | TokenFlagsUnicodeEscape | TokenFlagsExtendedUnicodeEscape | TokenFlagsContainsInvalidEscape
+ TokenFlagsNumericLiteralFlags TokenFlags = TokenFlagsScientific | TokenFlagsOctal | TokenFlagsContainsLeadingZero | TokenFlagsWithSpecifier | TokenFlagsContainsSeparator | TokenFlagsContainsInvalidSeparator
+ TokenFlagsTemplateLiteralLikeFlags TokenFlags = TokenFlagsHexEscape | TokenFlagsUnicodeEscape | TokenFlagsExtendedUnicodeEscape | TokenFlagsContainsInvalidEscape
+ TokenFlagsIsInvalid TokenFlags = TokenFlagsOctal | TokenFlagsContainsLeadingZero | TokenFlagsContainsInvalidSeparator | TokenFlagsContainsInvalidEscape
+)
+
+type EscapeSequenceScanningFlags int32
+
+const (
+ EscapeSequenceScanningFlagsString EscapeSequenceScanningFlags = 1 << 0
+ EscapeSequenceScanningFlagsReportErrors EscapeSequenceScanningFlags = 1 << 1
+ EscapeSequenceScanningFlagsRegularExpression EscapeSequenceScanningFlags = 1 << 2
+ EscapeSequenceScanningFlagsAnnexB EscapeSequenceScanningFlags = 1 << 3
+ EscapeSequenceScanningFlagsAnyUnicodeMode EscapeSequenceScanningFlags = 1 << 4
+ EscapeSequenceScanningFlagsAtomEscape EscapeSequenceScanningFlags = 1 << 5
+ EscapeSequenceScanningFlagsReportInvalidEscapeErrors EscapeSequenceScanningFlags = EscapeSequenceScanningFlagsRegularExpression | EscapeSequenceScanningFlagsReportErrors
+ EscapeSequenceScanningFlagsAllowExtendedUnicodeEscape EscapeSequenceScanningFlags = EscapeSequenceScanningFlagsString | EscapeSequenceScanningFlagsAnyUnicodeMode
+)
+
+type ErrorCallback func(diagnostic *diagnostics.Message, start, length int, args ...any)
+
+var textToKeyword = map[string]SyntaxKind{
+ "abstract": SyntaxKindAbstractKeyword,
+ "accessor": SyntaxKindAccessorKeyword,
+ "any": SyntaxKindAnyKeyword,
+ "as": SyntaxKindAsKeyword,
+ "asserts": SyntaxKindAssertsKeyword,
+ "assert": SyntaxKindAssertKeyword,
+ "bigint": SyntaxKindBigIntKeyword,
+ "boolean": SyntaxKindBooleanKeyword,
+ "break": SyntaxKindBreakKeyword,
+ "case": SyntaxKindCaseKeyword,
+ "catch": SyntaxKindCatchKeyword,
+ "class": SyntaxKindClassKeyword,
+ "continue": SyntaxKindContinueKeyword,
+ "const": SyntaxKindConstKeyword,
+ "constructor": SyntaxKindConstructorKeyword,
+ "debugger": SyntaxKindDebuggerKeyword,
+ "declare": SyntaxKindDeclareKeyword,
+ "default": SyntaxKindDefaultKeyword,
+ "delete": SyntaxKindDeleteKeyword,
+ "do": SyntaxKindDoKeyword,
+ "else": SyntaxKindElseKeyword,
+ "enum": SyntaxKindEnumKeyword,
+ "export": SyntaxKindExportKeyword,
+ "extends": SyntaxKindExtendsKeyword,
+ "false": SyntaxKindFalseKeyword,
+ "finally": SyntaxKindFinallyKeyword,
+ "for": SyntaxKindForKeyword,
+ "from": SyntaxKindFromKeyword,
+ "function": SyntaxKindFunctionKeyword,
+ "get": SyntaxKindGetKeyword,
+ "if": SyntaxKindIfKeyword,
+ "immediate": SyntaxKindImmediateKeyword,
+ "implements": SyntaxKindImplementsKeyword,
+ "import": SyntaxKindImportKeyword,
+ "in": SyntaxKindInKeyword,
+ "infer": SyntaxKindInferKeyword,
+ "instanceof": SyntaxKindInstanceOfKeyword,
+ "interface": SyntaxKindInterfaceKeyword,
+ "intrinsic": SyntaxKindIntrinsicKeyword,
+ "is": SyntaxKindIsKeyword,
+ "keyof": SyntaxKindKeyOfKeyword,
+ "let": SyntaxKindLetKeyword,
+ "module": SyntaxKindModuleKeyword,
+ "namespace": SyntaxKindNamespaceKeyword,
+ "never": SyntaxKindNeverKeyword,
+ "new": SyntaxKindNewKeyword,
+ "null": SyntaxKindNullKeyword,
+ "number": SyntaxKindNumberKeyword,
+ "object": SyntaxKindObjectKeyword,
+ "package": SyntaxKindPackageKeyword,
+ "private": SyntaxKindPrivateKeyword,
+ "protected": SyntaxKindProtectedKeyword,
+ "public": SyntaxKindPublicKeyword,
+ "override": SyntaxKindOverrideKeyword,
+ "out": SyntaxKindOutKeyword,
+ "readonly": SyntaxKindReadonlyKeyword,
+ "require": SyntaxKindRequireKeyword,
+ "global": SyntaxKindGlobalKeyword,
+ "return": SyntaxKindReturnKeyword,
+ "satisfies": SyntaxKindSatisfiesKeyword,
+ "set": SyntaxKindSetKeyword,
+ "static": SyntaxKindStaticKeyword,
+ "string": SyntaxKindStringKeyword,
+ "super": SyntaxKindSuperKeyword,
+ "switch": SyntaxKindSwitchKeyword,
+ "symbol": SyntaxKindSymbolKeyword,
+ "this": SyntaxKindThisKeyword,
+ "throw": SyntaxKindThrowKeyword,
+ "true": SyntaxKindTrueKeyword,
+ "try": SyntaxKindTryKeyword,
+ "type": SyntaxKindTypeKeyword,
+ "typeof": SyntaxKindTypeOfKeyword,
+ "undefined": SyntaxKindUndefinedKeyword,
+ "unique": SyntaxKindUniqueKeyword,
+ "unknown": SyntaxKindUnknownKeyword,
+ "using": SyntaxKindUsingKeyword,
+ "var": SyntaxKindVarKeyword,
+ "void": SyntaxKindVoidKeyword,
+ "while": SyntaxKindWhileKeyword,
+ "with": SyntaxKindWithKeyword,
+ "yield": SyntaxKindYieldKeyword,
+ "async": SyntaxKindAsyncKeyword,
+ "await": SyntaxKindAwaitKeyword,
+ "of": SyntaxKindOfKeyword,
+}
+
+var textToToken = map[string]SyntaxKind{
+ "{": SyntaxKindOpenBraceToken,
+ "}": SyntaxKindCloseBraceToken,
+ "(": SyntaxKindOpenParenToken,
+ ")": SyntaxKindCloseParenToken,
+ "[": SyntaxKindOpenBracketToken,
+ "]": SyntaxKindCloseBracketToken,
+ ".": SyntaxKindDotToken,
+ "...": SyntaxKindDotDotDotToken,
+ ";": SyntaxKindSemicolonToken,
+ ",": SyntaxKindCommaToken,
+ "<": SyntaxKindLessThanToken,
+ ">": SyntaxKindGreaterThanToken,
+ "<=": SyntaxKindLessThanEqualsToken,
+ ">=": SyntaxKindGreaterThanEqualsToken,
+ "==": SyntaxKindEqualsEqualsToken,
+ "!=": SyntaxKindExclamationEqualsToken,
+ "===": SyntaxKindEqualsEqualsEqualsToken,
+ "!==": SyntaxKindExclamationEqualsEqualsToken,
+ "=>": SyntaxKindEqualsGreaterThanToken,
+ "+": SyntaxKindPlusToken,
+ "-": SyntaxKindMinusToken,
+ "**": SyntaxKindAsteriskAsteriskToken,
+ "*": SyntaxKindAsteriskToken,
+ "/": SyntaxKindSlashToken,
+ "%": SyntaxKindPercentToken,
+ "++": SyntaxKindPlusPlusToken,
+ "--": SyntaxKindMinusMinusToken,
+ "<<": SyntaxKindLessThanLessThanToken,
+ "": SyntaxKindLessThanSlashToken,
+ ">>": SyntaxKindGreaterThanGreaterThanToken,
+ ">>>": SyntaxKindGreaterThanGreaterThanGreaterThanToken,
+ "&": SyntaxKindAmpersandToken,
+ "|": SyntaxKindBarToken,
+ "^": SyntaxKindCaretToken,
+ "!": SyntaxKindExclamationToken,
+ "~": SyntaxKindTildeToken,
+ "&&": SyntaxKindAmpersandAmpersandToken,
+ "||": SyntaxKindBarBarToken,
+ "?": SyntaxKindQuestionToken,
+ "??": SyntaxKindQuestionQuestionToken,
+ "?.": SyntaxKindQuestionDotToken,
+ ":": SyntaxKindColonToken,
+ "=": SyntaxKindEqualsToken,
+ "+=": SyntaxKindPlusEqualsToken,
+ "-=": SyntaxKindMinusEqualsToken,
+ "*=": SyntaxKindAsteriskEqualsToken,
+ "**=": SyntaxKindAsteriskAsteriskEqualsToken,
+ "/=": SyntaxKindSlashEqualsToken,
+ "%=": SyntaxKindPercentEqualsToken,
+ "<<=": SyntaxKindLessThanLessThanEqualsToken,
+ ">>=": SyntaxKindGreaterThanGreaterThanEqualsToken,
+ ">>>=": SyntaxKindGreaterThanGreaterThanGreaterThanEqualsToken,
+ "&=": SyntaxKindAmpersandEqualsToken,
+ "|=": SyntaxKindBarEqualsToken,
+ "^=": SyntaxKindCaretEqualsToken,
+ "||=": SyntaxKindBarBarEqualsToken,
+ "&&=": SyntaxKindAmpersandAmpersandEqualsToken,
+ "??=": SyntaxKindQuestionQuestionEqualsToken,
+ "@": SyntaxKindAtToken,
+ "#": SyntaxKindHashToken,
+ "`": SyntaxKindBacktickToken,
+}
+
+// As per ECMAScript Language Specification 5th Edition, Section 7.6: ISyntaxToken Names and Identifiers
+// IdentifierStart ::
+//
+// Can contain Unicode 6.2 categories:
+// Uppercase letter (Lu),
+// Lowercase letter (Ll),
+// Titlecase letter (Lt),
+// Modifier letter (Lm),
+// Other letter (Lo), or
+// Letter number (Nl).
+//
+// IdentifierPart ::
+//
+// Can contain IdentifierStart + Unicode 6.2 categories:
+// Non-spacing mark (Mn),
+// Combining spacing mark (Mc),
+// Decimal number (Nd),
+// Connector punctuation (Pc),
+// , or
+// .
+//
+// Codepoint ranges for ES5 Identifiers are extracted from the Unicode 6.2 specification at:
+// http://www.unicode.org/Public/6.2.0/ucd/UnicodeData.txt
+var unicodeES5IdentifierStart = []rune{170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2208, 2208, 2210, 2220, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, 7413, 7414, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500}
+var unicodeES5IdentifierPart = []rune{170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1520, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2048, 2093, 2112, 2139, 2208, 2208, 2210, 2220, 2276, 2302, 2304, 2403, 2406, 2415, 2417, 2423, 2425, 2431, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3161, 3168, 3171, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3299, 3302, 3311, 3313, 3314, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3396, 3398, 3400, 3402, 3406, 3415, 3415, 3424, 3427, 3430, 3439, 3450, 3455, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5908, 5920, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6160, 6169, 6176, 6263, 6272, 6314, 6320, 6389, 6400, 6428, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6617, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6912, 6987, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7376, 7378, 7380, 7414, 7424, 7654, 7676, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8204, 8205, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 11823, 11823, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12442, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42647, 42655, 42737, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43047, 43072, 43123, 43136, 43204, 43216, 43225, 43232, 43255, 43259, 43259, 43264, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43643, 43648, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65062, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500}
+
+// Generated by scripts/regenerate-unicode-identifier-parts.mjs on node v22.1.0 with unicode 15.1
+// based on http://www.unicode.org/reports/tr31/ and https://www.ecma-international.org/ecma-262/6.0/#sec-names-and-keywords
+// unicodeESNextIdentifierStart corresponds to the ID_Start and Other_ID_Start property, and
+// unicodeESNextIdentifierPart corresponds to ID_Continue, Other_ID_Continue, plus ID_Start and Other_ID_Start
+var unicodeESNextIdentifierStart = []rune{65, 90, 97, 122, 170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 895, 895, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1327, 1329, 1366, 1369, 1369, 1376, 1416, 1488, 1514, 1519, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2144, 2154, 2160, 2183, 2185, 2190, 2208, 2249, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2432, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2556, 2556, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2809, 2809, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3129, 3133, 3133, 3160, 3162, 3165, 3165, 3168, 3169, 3200, 3200, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3293, 3294, 3296, 3297, 3313, 3314, 3332, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3412, 3414, 3423, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3718, 3722, 3724, 3747, 3749, 3749, 3751, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5109, 5112, 5117, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5880, 5888, 5905, 5919, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6264, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6430, 6480, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6988, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7296, 7304, 7312, 7354, 7357, 7359, 7401, 7404, 7406, 7411, 7413, 7414, 7418, 7418, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8472, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12443, 12447, 12449, 12538, 12540, 12543, 12549, 12591, 12593, 12686, 12704, 12735, 12784, 12799, 13312, 19903, 19968, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42653, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42954, 42960, 42961, 42963, 42963, 42965, 42969, 42994, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43261, 43262, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43488, 43492, 43494, 43503, 43514, 43518, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43646, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43824, 43866, 43868, 43881, 43888, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, 65856, 65908, 66176, 66204, 66208, 66256, 66304, 66335, 66349, 66378, 66384, 66421, 66432, 66461, 66464, 66499, 66504, 66511, 66513, 66517, 66560, 66717, 66736, 66771, 66776, 66811, 66816, 66855, 66864, 66915, 66928, 66938, 66940, 66954, 66956, 66962, 66964, 66965, 66967, 66977, 66979, 66993, 66995, 67001, 67003, 67004, 67072, 67382, 67392, 67413, 67424, 67431, 67456, 67461, 67463, 67504, 67506, 67514, 67584, 67589, 67592, 67592, 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, 67680, 67702, 67712, 67742, 67808, 67826, 67828, 67829, 67840, 67861, 67872, 67897, 67968, 68023, 68030, 68031, 68096, 68096, 68112, 68115, 68117, 68119, 68121, 68149, 68192, 68220, 68224, 68252, 68288, 68295, 68297, 68324, 68352, 68405, 68416, 68437, 68448, 68466, 68480, 68497, 68608, 68680, 68736, 68786, 68800, 68850, 68864, 68899, 69248, 69289, 69296, 69297, 69376, 69404, 69415, 69415, 69424, 69445, 69488, 69505, 69552, 69572, 69600, 69622, 69635, 69687, 69745, 69746, 69749, 69749, 69763, 69807, 69840, 69864, 69891, 69926, 69956, 69956, 69959, 69959, 69968, 70002, 70006, 70006, 70019, 70066, 70081, 70084, 70106, 70106, 70108, 70108, 70144, 70161, 70163, 70187, 70207, 70208, 70272, 70278, 70280, 70280, 70282, 70285, 70287, 70301, 70303, 70312, 70320, 70366, 70405, 70412, 70415, 70416, 70419, 70440, 70442, 70448, 70450, 70451, 70453, 70457, 70461, 70461, 70480, 70480, 70493, 70497, 70656, 70708, 70727, 70730, 70751, 70753, 70784, 70831, 70852, 70853, 70855, 70855, 71040, 71086, 71128, 71131, 71168, 71215, 71236, 71236, 71296, 71338, 71352, 71352, 71424, 71450, 71488, 71494, 71680, 71723, 71840, 71903, 71935, 71942, 71945, 71945, 71948, 71955, 71957, 71958, 71960, 71983, 71999, 71999, 72001, 72001, 72096, 72103, 72106, 72144, 72161, 72161, 72163, 72163, 72192, 72192, 72203, 72242, 72250, 72250, 72272, 72272, 72284, 72329, 72349, 72349, 72368, 72440, 72704, 72712, 72714, 72750, 72768, 72768, 72818, 72847, 72960, 72966, 72968, 72969, 72971, 73008, 73030, 73030, 73056, 73061, 73063, 73064, 73066, 73097, 73112, 73112, 73440, 73458, 73474, 73474, 73476, 73488, 73490, 73523, 73648, 73648, 73728, 74649, 74752, 74862, 74880, 75075, 77712, 77808, 77824, 78895, 78913, 78918, 82944, 83526, 92160, 92728, 92736, 92766, 92784, 92862, 92880, 92909, 92928, 92975, 92992, 92995, 93027, 93047, 93053, 93071, 93760, 93823, 93952, 94026, 94032, 94032, 94099, 94111, 94176, 94177, 94179, 94179, 94208, 100343, 100352, 101589, 101632, 101640, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110882, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110951, 110960, 111355, 113664, 113770, 113776, 113788, 113792, 113800, 113808, 113817, 119808, 119892, 119894, 119964, 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, 122624, 122654, 122661, 122666, 122928, 122989, 123136, 123180, 123191, 123197, 123214, 123214, 123536, 123565, 123584, 123627, 124112, 124139, 124896, 124902, 124904, 124907, 124909, 124910, 124912, 124926, 124928, 125124, 125184, 125251, 125259, 125259, 126464, 126467, 126469, 126495, 126497, 126498, 126500, 126500, 126503, 126503, 126505, 126514, 126516, 126519, 126521, 126521, 126523, 126523, 126530, 126530, 126535, 126535, 126537, 126537, 126539, 126539, 126541, 126543, 126545, 126546, 126548, 126548, 126551, 126551, 126553, 126553, 126555, 126555, 126557, 126557, 126559, 126559, 126561, 126562, 126564, 126564, 126567, 126570, 126572, 126578, 126580, 126583, 126585, 126588, 126590, 126590, 126592, 126601, 126603, 126619, 126625, 126627, 126629, 126633, 126635, 126651, 131072, 173791, 173824, 177977, 177984, 178205, 178208, 183969, 183984, 191456, 191472, 192093, 194560, 195101, 196608, 201546, 201552, 205743}
+var unicodeESNextIdentifierPart = []rune{48, 57, 65, 90, 95, 95, 97, 122, 170, 170, 181, 181, 183, 183, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 895, 895, 902, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1327, 1329, 1366, 1369, 1369, 1376, 1416, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1519, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2045, 2045, 2048, 2093, 2112, 2139, 2144, 2154, 2160, 2183, 2185, 2190, 2200, 2273, 2275, 2403, 2406, 2415, 2417, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2556, 2556, 2558, 2558, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2809, 2815, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2901, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3072, 3084, 3086, 3088, 3090, 3112, 3114, 3129, 3132, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3162, 3165, 3165, 3168, 3171, 3174, 3183, 3200, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3293, 3294, 3296, 3299, 3302, 3311, 3313, 3315, 3328, 3340, 3342, 3344, 3346, 3396, 3398, 3400, 3402, 3406, 3412, 3415, 3423, 3427, 3430, 3439, 3450, 3455, 3457, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3558, 3567, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3718, 3722, 3724, 3747, 3749, 3749, 3751, 3773, 3776, 3780, 3782, 3782, 3784, 3790, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4969, 4977, 4992, 5007, 5024, 5109, 5112, 5117, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5880, 5888, 5909, 5919, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6159, 6169, 6176, 6264, 6272, 6314, 6320, 6389, 6400, 6430, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6618, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6832, 6845, 6847, 6862, 6912, 6988, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7296, 7304, 7312, 7354, 7357, 7359, 7376, 7378, 7380, 7418, 7424, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8204, 8205, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8472, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12447, 12449, 12543, 12549, 12591, 12593, 12686, 12704, 12735, 12784, 12799, 13312, 19903, 19968, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42737, 42775, 42783, 42786, 42888, 42891, 42954, 42960, 42961, 42963, 42963, 42965, 42969, 42994, 43047, 43052, 43052, 43072, 43123, 43136, 43205, 43216, 43225, 43232, 43255, 43259, 43259, 43261, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43488, 43518, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43824, 43866, 43868, 43881, 43888, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65071, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65381, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, 65856, 65908, 66045, 66045, 66176, 66204, 66208, 66256, 66272, 66272, 66304, 66335, 66349, 66378, 66384, 66426, 66432, 66461, 66464, 66499, 66504, 66511, 66513, 66517, 66560, 66717, 66720, 66729, 66736, 66771, 66776, 66811, 66816, 66855, 66864, 66915, 66928, 66938, 66940, 66954, 66956, 66962, 66964, 66965, 66967, 66977, 66979, 66993, 66995, 67001, 67003, 67004, 67072, 67382, 67392, 67413, 67424, 67431, 67456, 67461, 67463, 67504, 67506, 67514, 67584, 67589, 67592, 67592, 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, 67680, 67702, 67712, 67742, 67808, 67826, 67828, 67829, 67840, 67861, 67872, 67897, 67968, 68023, 68030, 68031, 68096, 68099, 68101, 68102, 68108, 68115, 68117, 68119, 68121, 68149, 68152, 68154, 68159, 68159, 68192, 68220, 68224, 68252, 68288, 68295, 68297, 68326, 68352, 68405, 68416, 68437, 68448, 68466, 68480, 68497, 68608, 68680, 68736, 68786, 68800, 68850, 68864, 68903, 68912, 68921, 69248, 69289, 69291, 69292, 69296, 69297, 69373, 69404, 69415, 69415, 69424, 69456, 69488, 69509, 69552, 69572, 69600, 69622, 69632, 69702, 69734, 69749, 69759, 69818, 69826, 69826, 69840, 69864, 69872, 69881, 69888, 69940, 69942, 69951, 69956, 69959, 69968, 70003, 70006, 70006, 70016, 70084, 70089, 70092, 70094, 70106, 70108, 70108, 70144, 70161, 70163, 70199, 70206, 70209, 70272, 70278, 70280, 70280, 70282, 70285, 70287, 70301, 70303, 70312, 70320, 70378, 70384, 70393, 70400, 70403, 70405, 70412, 70415, 70416, 70419, 70440, 70442, 70448, 70450, 70451, 70453, 70457, 70459, 70468, 70471, 70472, 70475, 70477, 70480, 70480, 70487, 70487, 70493, 70499, 70502, 70508, 70512, 70516, 70656, 70730, 70736, 70745, 70750, 70753, 70784, 70853, 70855, 70855, 70864, 70873, 71040, 71093, 71096, 71104, 71128, 71133, 71168, 71232, 71236, 71236, 71248, 71257, 71296, 71352, 71360, 71369, 71424, 71450, 71453, 71467, 71472, 71481, 71488, 71494, 71680, 71738, 71840, 71913, 71935, 71942, 71945, 71945, 71948, 71955, 71957, 71958, 71960, 71989, 71991, 71992, 71995, 72003, 72016, 72025, 72096, 72103, 72106, 72151, 72154, 72161, 72163, 72164, 72192, 72254, 72263, 72263, 72272, 72345, 72349, 72349, 72368, 72440, 72704, 72712, 72714, 72758, 72760, 72768, 72784, 72793, 72818, 72847, 72850, 72871, 72873, 72886, 72960, 72966, 72968, 72969, 72971, 73014, 73018, 73018, 73020, 73021, 73023, 73031, 73040, 73049, 73056, 73061, 73063, 73064, 73066, 73102, 73104, 73105, 73107, 73112, 73120, 73129, 73440, 73462, 73472, 73488, 73490, 73530, 73534, 73538, 73552, 73561, 73648, 73648, 73728, 74649, 74752, 74862, 74880, 75075, 77712, 77808, 77824, 78895, 78912, 78933, 82944, 83526, 92160, 92728, 92736, 92766, 92768, 92777, 92784, 92862, 92864, 92873, 92880, 92909, 92912, 92916, 92928, 92982, 92992, 92995, 93008, 93017, 93027, 93047, 93053, 93071, 93760, 93823, 93952, 94026, 94031, 94087, 94095, 94111, 94176, 94177, 94179, 94180, 94192, 94193, 94208, 100343, 100352, 101589, 101632, 101640, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110882, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110951, 110960, 111355, 113664, 113770, 113776, 113788, 113792, 113800, 113808, 113817, 113821, 113822, 118528, 118573, 118576, 118598, 119141, 119145, 119149, 119154, 119163, 119170, 119173, 119179, 119210, 119213, 119362, 119364, 119808, 119892, 119894, 119964, 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, 120782, 120831, 121344, 121398, 121403, 121452, 121461, 121461, 121476, 121476, 121499, 121503, 121505, 121519, 122624, 122654, 122661, 122666, 122880, 122886, 122888, 122904, 122907, 122913, 122915, 122916, 122918, 122922, 122928, 122989, 123023, 123023, 123136, 123180, 123184, 123197, 123200, 123209, 123214, 123214, 123536, 123566, 123584, 123641, 124112, 124153, 124896, 124902, 124904, 124907, 124909, 124910, 124912, 124926, 124928, 125124, 125136, 125142, 125184, 125259, 125264, 125273, 126464, 126467, 126469, 126495, 126497, 126498, 126500, 126500, 126503, 126503, 126505, 126514, 126516, 126519, 126521, 126521, 126523, 126523, 126530, 126530, 126535, 126535, 126537, 126537, 126539, 126539, 126541, 126543, 126545, 126546, 126548, 126548, 126551, 126551, 126553, 126553, 126555, 126555, 126557, 126557, 126559, 126559, 126561, 126562, 126564, 126564, 126567, 126570, 126572, 126578, 126580, 126583, 126585, 126588, 126590, 126590, 126592, 126601, 126603, 126619, 126625, 126627, 126629, 126633, 126635, 126651, 130032, 130041, 131072, 173791, 173824, 177977, 177984, 178205, 178208, 183969, 183984, 191456, 191472, 192093, 194560, 195101, 196608, 201546, 201552, 205743, 917760, 917999}
+
+type ScannerState struct {
+ pos int // Current position in text (and ending position of current token)
+ fullStartPos int // Starting position of current token including preceding whitespace
+ tokenStart int // Starting position of non-whitespace part of current token
+ token SyntaxKind // SyntaxKind of current token
+ tokenValue string // Parsed value of current token
+ tokenFlags TokenFlags // Flags for current token
+}
+
+type Scanner struct {
+ text string
+ languageVersion ScriptTarget
+ languageVariant LanguageVariant
+ onError ErrorCallback
+ ScannerState
+}
+
+func NewScanner() *Scanner {
+ return &Scanner{languageVersion: ScriptTargetLatest}
+}
+
+func (s *Scanner) Text() string {
+ return s.text
+}
+
+func (s *Scanner) Token() SyntaxKind {
+ return s.token
+}
+
+func (s *Scanner) TokenFullStart() int {
+ return s.fullStartPos
+}
+
+func (s *Scanner) TokenStart() int {
+ return s.tokenStart
+}
+
+func (s *Scanner) TokenEnd() int {
+ return s.pos
+}
+
+func (s *Scanner) TokenText() string {
+ return s.text[s.tokenStart:s.pos]
+}
+
+func (s *Scanner) TokenValue() string {
+ return s.tokenValue
+}
+
+func (s *Scanner) TokenRange() TextRange {
+ return NewTextRange(s.tokenStart, s.pos)
+}
+
+func (s *Scanner) Mark() ScannerState {
+ return s.ScannerState
+}
+
+func (s *Scanner) Rewind(state ScannerState) {
+ s.ScannerState = state
+}
+
+func (s *Scanner) HasUnicodeEscape() bool {
+ return s.tokenFlags&TokenFlagsUnicodeEscape != 0
+}
+
+func (s *Scanner) HasExtendedUnicodeEscape() bool {
+ return s.tokenFlags&TokenFlagsExtendedUnicodeEscape != 0
+}
+
+func (s *Scanner) HasPrecedingLineBreak() bool {
+ return s.tokenFlags&TokenFlagsPrecedingLineBreak != 0
+}
+
+func (s *Scanner) SetText(text string) {
+ s.text = text
+ s.ScannerState = ScannerState{}
+}
+
+func (s *Scanner) SetOnError(errorCallback ErrorCallback) {
+ s.onError = errorCallback
+}
+
+func (s *Scanner) SetScriptTarget(scriptTarget ScriptTarget) {
+ s.languageVersion = scriptTarget
+}
+
+func (s *Scanner) SetLanguageVariant(languageVariant LanguageVariant) {
+ s.languageVariant = languageVariant
+}
+
+func (s *Scanner) error(diagnostic *diagnostics.Message) {
+ s.errorAt(diagnostic, s.pos, 0)
+}
+
+func (s *Scanner) errorAt(diagnostic *diagnostics.Message, pos int, len int, args ...any) {
+ if s.onError != nil {
+ s.onError(diagnostic, pos, len, args...)
+ }
+}
+
+func (s *Scanner) char() rune {
+ if s.pos < len(s.text) {
+ return rune(s.text[s.pos])
+ }
+ return -1
+}
+
+func (s *Scanner) charAt(offset int) rune {
+ if s.pos+offset < len(s.text) {
+ return rune(s.text[s.pos+offset])
+ }
+ return -1
+}
+
+func (s *Scanner) charAndSize() (rune, int) {
+ return utf8.DecodeRuneInString(s.text[s.pos:])
+}
+
+func (s *Scanner) shouldParseJSDoc() bool {
+ return false
+}
+
+func (s *Scanner) Scan() SyntaxKind {
+ s.fullStartPos = s.pos
+ s.tokenFlags = TokenFlagsNone
+ for {
+ s.tokenStart = s.pos
+ ch := s.char()
+ switch ch {
+ case '\t', '\v', '\f', ' ':
+ s.pos++
+ continue
+ case '\n', '\r':
+ s.tokenFlags |= TokenFlagsPrecedingLineBreak
+ s.pos++
+ continue
+ case '!':
+ if s.charAt(1) == '=' {
+ if s.charAt(2) == '=' {
+ s.pos += 3
+ s.token = SyntaxKindExclamationEqualsEqualsToken
+ } else {
+ s.pos += 2
+ s.token = SyntaxKindExclamationEqualsToken
+ }
+ } else {
+ s.pos++
+ s.token = SyntaxKindExclamationToken
+ }
+ case '"', '\'':
+ s.tokenValue = s.scanString(false /*jsxAttributeString*/)
+ s.token = SyntaxKindStringLiteral
+ case '`':
+ s.token = s.scanTemplateAndSetTokenValue(false /*shouldEmitInvalidEscapeError*/)
+ case '%':
+ if s.charAt(1) == '=' {
+ s.pos += 2
+ s.token = SyntaxKindPercentEqualsToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindPercentToken
+ }
+ case '&':
+ if s.charAt(1) == '&' {
+ if s.charAt(2) == '=' {
+ s.pos += 3
+ s.token = SyntaxKindAmpersandAmpersandEqualsToken
+ } else {
+ s.pos += 2
+ s.token = SyntaxKindAmpersandAmpersandToken
+ }
+ } else if s.charAt(1) == '=' {
+ s.pos += 2
+ s.token = SyntaxKindAmpersandEqualsToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindAmpersandToken
+ }
+ case '(':
+ s.pos++
+ s.token = SyntaxKindOpenParenToken
+ case ')':
+ s.pos++
+ s.token = SyntaxKindCloseParenToken
+ case '*':
+ if s.charAt(1) == '=' {
+ s.pos += 2
+ s.token = SyntaxKindAsteriskEqualsToken
+ } else if s.charAt(1) == '*' {
+ s.pos += 2
+ s.token = SyntaxKindAsteriskAsteriskToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindAsteriskToken
+ }
+ case '+':
+ if s.charAt(1) == '=' {
+ s.pos += 2
+ s.token = SyntaxKindPlusEqualsToken
+ } else if s.charAt(1) == '+' {
+ s.pos += 2
+ s.token = SyntaxKindPlusPlusToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindPlusToken
+ }
+ case ',':
+ s.pos++
+ s.token = SyntaxKindCommaToken
+ case '-':
+ if s.charAt(1) == '=' {
+ s.pos += 2
+ s.token = SyntaxKindMinusEqualsToken
+ } else if s.charAt(1) == '-' {
+ s.pos += 2
+ s.token = SyntaxKindMinusMinusToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindMinusToken
+ }
+ case '.':
+ if isDigit(s.charAt(1)) {
+ s.token = s.scanNumber()
+ } else if s.charAt(1) == '.' && s.charAt(2) == '.' {
+ s.pos += 3
+ s.token = SyntaxKindDotDotDotToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindDotToken
+ }
+ case '/':
+ if s.charAt(1) == '/' {
+ s.pos += 2
+ for {
+ ch := s.char()
+ if ch <= 0x7F {
+ if ch < 0 || ch == '\r' || ch == '\n' {
+ break
+ }
+ s.pos++
+ } else {
+ ch, size := s.charAndSize()
+ if isLineBreak(ch) {
+ break
+ }
+ s.pos += size
+ }
+ }
+ // commentDirectives = appendIfCommentDirective(commentDirectives, text.slice(tokenStart, pos), commentDirectiveRegExSingleLine, tokenStart);
+ continue
+ }
+ if s.charAt(1) == '*' {
+ s.pos += 2
+ isJSDoc := s.char() == '*' && s.charAt(1) != '/'
+ for {
+ ch = s.char()
+ if ch <= 0x7F {
+ if ch < 0 {
+ s.error(diagnostics.Asterisk_Slash_expected)
+ break
+ }
+ if ch == '*' && s.charAt(1) == '/' {
+ s.pos += 2
+ break
+ }
+ if ch == '\r' || ch == '\n' {
+ s.tokenFlags |= TokenFlagsPrecedingLineBreak
+ }
+ s.pos++
+ } else {
+ ch, size := s.charAndSize()
+ if isLineBreak(ch) {
+ break
+ }
+ s.pos += size
+ }
+ }
+ if isJSDoc && s.shouldParseJSDoc() {
+ s.tokenFlags |= TokenFlagsPrecedingJSDocComment
+ }
+ // commentDirectives = appendIfCommentDirective(commentDirectives, text.slice(lastLineStart, pos), commentDirectiveRegExMultiLine, lastLineStart);
+ continue
+ }
+ if s.charAt(1) == '=' {
+ s.pos += 2
+ s.token = SyntaxKindSlashEqualsToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindSlashToken
+ }
+ case '0':
+ if s.charAt(1) == 'X' || s.charAt(1) == 'x' {
+ s.pos += 2
+ digits := s.scanHexDigits(1, true, true)
+ if digits == "" {
+ s.error(diagnostics.Hexadecimal_digit_expected)
+ digits = "0"
+ }
+ s.tokenValue = "0x" + digits
+ s.tokenFlags |= TokenFlagsHexSpecifier
+ s.token = s.scanBigIntSuffix()
+ break
+ }
+ if s.charAt(1) == 'B' || s.charAt(1) == 'b' {
+ s.pos += 2
+ digits := s.scanBinaryOrOctalDigits(2)
+ if digits == "" {
+ s.error(diagnostics.Binary_digit_expected)
+ digits = "0"
+ }
+ s.tokenValue = "0b" + digits
+ s.tokenFlags |= TokenFlagsBinarySpecifier
+ s.token = s.scanBigIntSuffix()
+ break
+ }
+ if s.charAt(1) == 'O' || s.charAt(1) == 'o' {
+ s.pos += 2
+ digits := s.scanBinaryOrOctalDigits(8)
+ if digits == "" {
+ s.error(diagnostics.Octal_digit_expected)
+ digits = "0"
+ }
+ s.tokenValue = "0o" + digits
+ s.tokenFlags |= TokenFlagsOctalSpecifier
+ s.token = s.scanBigIntSuffix()
+ break
+ }
+ fallthrough
+ case '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ s.token = s.scanNumber()
+ case ':':
+ s.pos++
+ s.token = SyntaxKindColonToken
+ case ';':
+ s.pos++
+ s.token = SyntaxKindSemicolonToken
+ case '<':
+ // Handle conflict marker trivia !!!
+ if s.charAt(1) == '<' {
+ if s.charAt(2) == '=' {
+ s.pos += 3
+ s.token = SyntaxKindLessThanLessThanEqualsToken
+ } else {
+ s.pos += 2
+ s.token = SyntaxKindLessThanLessThanToken
+ }
+ } else if s.charAt(1) == '=' {
+ s.pos += 2
+ s.token = SyntaxKindLessThanEqualsToken
+ } else if s.languageVariant == LanguageVariantJSX && s.charAt(1) == '/' && s.charAt(2) != '*' {
+ s.pos += 2
+ s.token = SyntaxKindLessThanSlashToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindLessThanToken
+ }
+ case '=':
+ // Handle conflict marker trivia !!!
+ if s.charAt(1) == '=' {
+ if s.charAt(2) == '=' {
+ s.pos += 3
+ s.token = SyntaxKindEqualsEqualsEqualsToken
+ } else {
+ s.pos += 2
+ s.token = SyntaxKindEqualsEqualsToken
+ }
+ } else if s.charAt(1) == '>' {
+ s.pos += 2
+ s.token = SyntaxKindEqualsGreaterThanToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindEqualsToken
+ }
+ case '>':
+ // Handle conflict marker trivia !!!
+ s.pos++
+ s.token = SyntaxKindGreaterThanToken
+ case '?':
+ if s.charAt(1) == '.' && !isDigit(s.charAt(2)) {
+ s.pos += 2
+ s.token = SyntaxKindQuestionDotToken
+ } else if s.charAt(1) == '?' {
+ if s.charAt(2) == '=' {
+ s.pos += 3
+ s.token = SyntaxKindQuestionQuestionEqualsToken
+ } else {
+ s.pos += 2
+ s.token = SyntaxKindQuestionQuestionToken
+ }
+ } else {
+ s.pos++
+ s.token = SyntaxKindQuestionToken
+ }
+ case '[':
+ s.pos++
+ s.token = SyntaxKindOpenBracketToken
+ case ']':
+ s.pos++
+ s.token = SyntaxKindCloseBracketToken
+ case '^':
+ if s.charAt(1) == '=' {
+ s.pos += 2
+ s.token = SyntaxKindCaretEqualsToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindCaretToken
+ }
+ case '{':
+ s.pos++
+ s.token = SyntaxKindOpenBraceToken
+ case '|':
+ // Handle conflict marker trivia !!!
+ if s.charAt(1) == '|' {
+ if s.charAt(2) == '=' {
+ s.pos += 3
+ s.token = SyntaxKindBarBarEqualsToken
+ } else {
+ s.pos += 2
+ s.token = SyntaxKindBarBarToken
+ }
+ } else if s.charAt(1) == '=' {
+ s.pos += 2
+ s.token = SyntaxKindBarEqualsToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindBarToken
+ }
+ case '}':
+ s.pos++
+ s.token = SyntaxKindCloseBraceToken
+ case '~':
+ s.pos++
+ s.token = SyntaxKindTildeToken
+ case '@':
+ s.pos++
+ s.token = SyntaxKindAtToken
+ case '\\':
+ cp := s.peekUnicodeEscape()
+ if cp >= 0 && isIdentifierStart(cp, s.languageVersion) {
+ s.tokenValue = string(s.scanUnicodeEscape(true)) + s.scanIdentifierParts()
+ s.token = getIdentifierToken(s.tokenValue)
+ } else {
+ s.scanInvalidCharacter()
+ }
+ case '#':
+ if s.charAt(1) == '!' {
+ if s.pos == 0 {
+ s.pos += 2
+ for s.char() >= 0 && s.char() != '\n' {
+ s.pos++
+ }
+ continue
+ }
+ s.errorAt(diagnostics.X_can_only_be_used_at_the_start_of_a_file, s.pos, 2)
+ s.pos += 2
+ s.token = SyntaxKindUnknown
+ break
+ }
+ if s.charAt(1) == '\\' {
+ s.pos++
+ cp := s.peekUnicodeEscape()
+ if cp >= 0 && isIdentifierStart(cp, s.languageVersion) {
+ s.tokenValue = "#" + string(s.scanUnicodeEscape(true)) + s.scanIdentifierParts()
+ s.token = SyntaxKindPrivateIdentifier
+ break
+ }
+ s.pos--
+ }
+ if s.scanIdentifier(1) {
+ s.token = SyntaxKindPrivateIdentifier
+ } else {
+ s.errorAt(diagnostics.Invalid_character, s.pos-1, 1)
+ s.token = SyntaxKindUnknown
+ }
+ default:
+ if ch < 0 {
+ s.token = SyntaxKindEndOfFile
+ break
+ }
+ if s.scanIdentifier(0) {
+ s.token = getIdentifierToken(s.tokenValue)
+ break
+ }
+ ch, size := s.charAndSize()
+ if ch == utf8.RuneError && size == 1 {
+ s.errorAt(diagnostics.File_appears_to_be_binary, 0, 0)
+ s.pos = len(s.text)
+ s.token = SyntaxKindNonTextFileMarkerTrivia
+ break
+ }
+ if isWhiteSpaceSingleLine(ch) {
+ s.pos += size
+ continue
+ }
+ if isLineBreak(ch) {
+ s.tokenFlags |= TokenFlagsPrecedingLineBreak
+ s.pos += size
+ continue
+ }
+ s.scanInvalidCharacter()
+ }
+ return s.token
+ }
+}
+
+func (s *Scanner) ReScanLessThanToken() SyntaxKind {
+ if s.token == SyntaxKindLessThanLessThanToken {
+ s.pos = s.tokenStart + 1
+ s.token = SyntaxKindLessThanToken
+ }
+ return s.token
+}
+
+func (s *Scanner) ReScanGreaterThanToken() SyntaxKind {
+ if s.token == SyntaxKindGreaterThanToken {
+ s.pos = s.tokenStart + 1
+ if s.char() == '>' {
+ if s.charAt(1) == '>' {
+ if s.charAt(2) == '=' {
+ s.pos += 3
+ s.token = SyntaxKindGreaterThanGreaterThanGreaterThanEqualsToken
+ } else {
+ s.pos += 2
+ s.token = SyntaxKindGreaterThanGreaterThanGreaterThanToken
+ }
+ } else if s.charAt(1) == '=' {
+ s.pos += 2
+ s.token = SyntaxKindGreaterThanGreaterThanEqualsToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindGreaterThanGreaterThanToken
+ }
+ } else if s.char() == '=' {
+ s.pos++
+ s.token = SyntaxKindGreaterThanEqualsToken
+ }
+ }
+ return s.token
+}
+
+func (s *Scanner) ReScanTemplateToken(isTaggedTemplate bool) SyntaxKind {
+ s.pos = s.tokenStart
+ s.token = s.scanTemplateAndSetTokenValue(!isTaggedTemplate)
+ return s.token
+}
+
+// !!! https://github.com/microsoft/TypeScript/pull/55600
+func (s *Scanner) ReScanSlashToken() SyntaxKind {
+ if s.token == SyntaxKindSlashToken || s.token == SyntaxKindSlashEqualsToken {
+ s.pos = s.tokenStart + 1
+ inEscape := false
+ inCharacterClass := false
+ loop:
+ for {
+ ch, size := s.charAndSize()
+ // If we reach the end of a file, or hit a newline, then this is an unterminated
+ // regex. Report error and return what we have so far.
+ switch {
+ case size == 0 || isLineBreak(ch):
+ s.tokenFlags |= TokenFlagsUnterminated
+ s.error(diagnostics.Unterminated_regular_expression_literal)
+ break loop
+ case inEscape:
+ // Parsing an escape character;
+ // reset the flag and just advance to the next char.
+ inEscape = false
+ case ch == '/' && !inCharacterClass:
+ // A slash within a character class is permissible,
+ // but in general it signals the end of the regexp literal.
+ s.pos++
+ break loop
+ case ch == '[':
+ inCharacterClass = true
+ case ch == '\\':
+ inEscape = true
+ case ch == ']':
+ inCharacterClass = false
+ }
+ s.pos += size
+ }
+ for {
+ ch, size := s.charAndSize()
+ if size == 0 || !isIdentifierPart(ch, s.languageVersion, s.languageVariant) {
+ break
+ }
+ s.pos += size
+ }
+ s.tokenValue = s.text[s.tokenStart:s.pos]
+ s.token = SyntaxKindRegularExpressionLiteral
+ }
+ return s.token
+}
+
+func (s *Scanner) reScanJsxToken(allowMultilineJsxText bool) SyntaxKind {
+ s.pos = s.fullStartPos
+ s.tokenStart = s.fullStartPos
+ s.token = s.scanJsxTokenEx(allowMultilineJsxText)
+ return s.token
+}
+
+func (s *Scanner) scanJsxToken() SyntaxKind {
+ return s.scanJsxTokenEx(true /*allowMultilineJsxText*/)
+}
+
+func (s *Scanner) scanJsxTokenEx(allowMultilineJsxText bool) SyntaxKind {
+ s.fullStartPos = s.pos
+ s.tokenStart = s.pos
+ ch := s.char()
+ switch {
+ case ch < 0:
+ s.token = SyntaxKindEndOfFile
+ case ch == '<':
+ if s.charAt(1) == '/' {
+ s.pos += 2
+ s.token = SyntaxKindLessThanSlashToken
+ } else {
+ s.pos++
+ s.token = SyntaxKindLessThanToken
+ }
+ case ch == '{':
+ s.pos++
+ s.token = SyntaxKindOpenBraceToken
+ default:
+ // First non-whitespace character on this line.
+ firstNonWhitespace := 0
+ // These initial values are special because the first line is:
+ // firstNonWhitespace = 0 to indicate that we want leading whitespace
+ for {
+ ch, size := s.charAndSize()
+ if size == 0 || ch == '{' {
+ break
+ }
+ if ch == '<' {
+ // !!!
+ // if (isConflictMarkerTrivia(text, pos)) {
+ // pos = scanConflictMarkerTrivia(text, pos, error);
+ // return token = SyntaxKind.ConflictMarkerTrivia;
+ // }
+ break
+ }
+ if ch == '>' {
+ s.errorAt(diagnostics.Unexpected_token_Did_you_mean_or_gt, s.pos, 1)
+ } else if ch == '}' {
+ s.errorAt(diagnostics.Unexpected_token_Did_you_mean_or_rbrace, s.pos, 1)
+ }
+ // FirstNonWhitespace is 0, then we only see whitespaces so far. If we see a linebreak, we want to ignore that whitespaces.
+ // i.e (- : whitespace)
+ // ----
+ //
becomes
+ //
+ // ----
becomes ----
+ if isLineBreak(ch) && firstNonWhitespace == 0 {
+ firstNonWhitespace = -1
+ } else if !allowMultilineJsxText && isLineBreak(ch) && firstNonWhitespace > 0 {
+ // Stop JsxText on each line during formatting. This allows the formatter to
+ // indent each line correctly.
+ break
+ } else if !isWhiteSpaceLike(ch) {
+ firstNonWhitespace = s.pos
+ }
+ s.pos += size
+ }
+ s.tokenValue = s.text[s.fullStartPos:s.pos]
+ s.token = SyntaxKindJsxText
+ if firstNonWhitespace == -1 {
+ s.token = SyntaxKindJsxTextAllWhiteSpaces
+ }
+ }
+ return s.token
+}
+
+// Scans a JSX identifier; these differ from normal identifiers in that they allow dashes
+func (s *Scanner) scanJsxIdentifier() SyntaxKind {
+ if tokenIsIdentifierOrKeyword(s.token) {
+ // An identifier or keyword has already been parsed - check for a `-` or a single instance of `:` and then append it and
+ // everything after it to the token
+ // Do note that this means that `scanJsxIdentifier` effectively _mutates_ the visible token without advancing to a new token
+ // Any caller should be expecting this behavior and should only read the pos or token value after calling it.
+ for {
+ ch := s.char()
+ if ch < 0 {
+ break
+ }
+ if ch == '-' {
+ s.tokenValue += "-"
+ s.pos++
+ continue
+ }
+ oldPos := s.pos
+ s.tokenValue += s.scanIdentifierParts() // reuse `scanIdentifierParts` so unicode escapes are handled
+ if s.pos == oldPos {
+ break
+ }
+ }
+ s.token = getIdentifierToken(s.tokenValue)
+ }
+ return s.token
+}
+
+func (s *Scanner) scanJsxAttributeValue() SyntaxKind {
+ s.fullStartPos = s.pos
+ switch s.char() {
+ case '"', '\'':
+ s.tokenValue = s.scanString(true /*jsxAttributeString*/)
+ s.token = SyntaxKindStringLiteral
+ return s.token
+ default:
+ // If this scans anything other than `{`, it's a parse error.
+ return s.Scan()
+ }
+}
+
+func (s *Scanner) reScanJsxAttributeValue() SyntaxKind {
+ s.pos = s.fullStartPos
+ s.tokenStart = s.fullStartPos
+ return s.scanJsxAttributeValue()
+}
+
+func (s *Scanner) scanIdentifier(prefixLength int) bool {
+ start := s.pos
+ s.pos += prefixLength
+ ch := s.char()
+ // Fast path for simple ASCII identifiers
+ if isASCIILetter(ch) || ch == '_' || ch == '$' {
+ for {
+ s.pos++
+ ch = s.char()
+ if !(isWordCharacter(ch) || ch == '$') {
+ break
+ }
+ }
+ if ch <= 0x7F || ch != '\\' {
+ s.tokenValue = s.text[start:s.pos]
+ return true
+ }
+ s.pos = start
+ }
+ ch, size := s.charAndSize()
+ if isIdentifierStart(ch, s.languageVersion) {
+ for {
+ s.pos += size
+ ch, size = s.charAndSize()
+ if !isIdentifierPart(ch, s.languageVersion, s.languageVariant) {
+ break
+ }
+ }
+ s.tokenValue = s.text[start:s.pos]
+ if ch == '\\' {
+ s.tokenValue += s.scanIdentifierParts()
+ }
+ return true
+ }
+ return false
+}
+
+func (s *Scanner) scanIdentifierParts() string {
+ var sb strings.Builder
+ start := s.pos
+ for {
+ ch, size := s.charAndSize()
+ if isIdentifierPart(ch, s.languageVersion, s.languageVariant) {
+ s.pos += size
+ continue
+ }
+ if ch == '\\' {
+ escaped := s.peekUnicodeEscape()
+ if escaped >= 0 && isIdentifierPart(escaped, s.languageVersion, s.languageVariant) {
+ sb.WriteString(s.text[start:s.pos])
+ sb.WriteString(string(s.scanUnicodeEscape(true)))
+ start = s.pos
+ continue
+ }
+ }
+ break
+ }
+ sb.WriteString(s.text[start:s.pos])
+ return sb.String()
+}
+
+func (s *Scanner) scanString(jsxAttributeString bool) string {
+ quote := s.char()
+ s.pos++
+ var sb strings.Builder
+ start := s.pos
+ for {
+ ch := s.char()
+ if ch < 0 {
+ sb.WriteString(s.text[start:s.pos])
+ s.tokenFlags |= TokenFlagsUnterminated
+ s.error(diagnostics.Unterminated_string_literal)
+ break
+ }
+ if ch == quote {
+ sb.WriteString(s.text[start:s.pos])
+ s.pos++
+ break
+ }
+ if ch == '\\' && !jsxAttributeString {
+ sb.WriteString(s.text[start:s.pos])
+ sb.WriteString(s.scanEscapeSequence(EscapeSequenceScanningFlagsString | EscapeSequenceScanningFlagsReportErrors))
+ start = s.pos
+ continue
+ }
+ if ch == '\n' || ch == '\r' && !jsxAttributeString {
+ sb.WriteString(s.text[start:s.pos])
+ s.tokenFlags |= TokenFlagsUnterminated
+ s.error(diagnostics.Unterminated_string_literal)
+ break
+ }
+ s.pos++
+ }
+ return sb.String()
+}
+
+func (s *Scanner) scanTemplateAndSetTokenValue(shouldEmitInvalidEscapeError bool) SyntaxKind {
+ startedWithBacktick := s.char() == '`'
+ start := s.pos
+ s.pos++
+ contents := ""
+ var token SyntaxKind
+ for {
+ ch := s.char()
+ if ch < 0 || ch == '`' {
+ contents += s.text[start:s.pos]
+ if ch == '`' {
+ s.pos++
+ } else {
+ s.tokenFlags |= TokenFlagsUnterminated
+ s.error(diagnostics.Unterminated_template_literal)
+ }
+ token = ifElse(startedWithBacktick, SyntaxKindNoSubstitutionTemplateLiteral, SyntaxKindTemplateTail)
+ break
+ }
+ if ch == '$' && s.charAt(1) == '{' {
+ contents += s.text[start:s.pos]
+ s.pos += 2
+ token = ifElse(startedWithBacktick, SyntaxKindTemplateHead, SyntaxKindTemplateMiddle)
+ break
+ }
+ if ch == '\\' {
+ contents += s.text[start:s.pos]
+ contents += s.scanEscapeSequence(EscapeSequenceScanningFlagsString | ifElse(shouldEmitInvalidEscapeError, EscapeSequenceScanningFlagsReportErrors, 0))
+ start = s.pos
+ continue
+ }
+ // Speculated ECMAScript 6 Spec 11.8.6.1:
+ // and LineTerminatorSequences are normalized to for Template Values
+ if ch == '\r' {
+ contents += s.text[start:s.pos]
+ s.pos++
+ if ch == '\n' {
+ s.pos++
+ }
+ contents += "\n"
+ start = s.pos
+ continue
+ }
+ s.pos++
+ }
+ s.tokenValue = contents
+ return token
+}
+
+func (s *Scanner) scanEscapeSequence(flags EscapeSequenceScanningFlags) string {
+ start := s.pos
+ s.pos++
+ ch := s.char()
+ if ch < 0 {
+ s.error(diagnostics.Unexpected_end_of_text)
+ return ""
+ }
+ s.pos++
+ switch ch {
+ case '0':
+ // Although '0' preceding any digit is treated as LegacyOctalEscapeSequence,
+ // '\08' should separately be interpreted as '\0' + '8'.
+ if !isDigit(s.char()) {
+ return "\x00"
+ }
+ // '\01', '\011'
+ fallthrough
+ case '1', '2', '3':
+ // '\1', '\17', '\177'
+ if isOctalDigit(s.char()) {
+ s.pos++
+ }
+ // '\17', '\177'
+ fallthrough
+ case '4', '5', '6', '7':
+ // '\4', '\47' but not '\477'
+ if isOctalDigit(s.char()) {
+ s.pos++
+ }
+ // '\47'
+ s.tokenFlags |= TokenFlagsContainsInvalidEscape
+ if flags&EscapeSequenceScanningFlagsReportInvalidEscapeErrors != 0 {
+ code, _ := strconv.ParseInt(s.text[start+1:s.pos], 8, 32)
+ if flags&EscapeSequenceScanningFlagsRegularExpression != 0 && flags&EscapeSequenceScanningFlagsAtomEscape == 0 && ch != '0' {
+ s.errorAt(diagnostics.Octal_escape_sequences_and_backreferences_are_not_allowed_in_a_character_class_If_this_was_intended_as_an_escape_sequence_use_the_syntax_0_instead, start, s.pos-start, fmt.Sprintf("%02x", code))
+ } else {
+ s.errorAt(diagnostics.Octal_escape_sequences_are_not_allowed_Use_the_syntax_0, start, s.pos-start, code)
+ }
+ return string(rune(code))
+ }
+ return s.text[start:s.pos]
+ case '8', '9':
+ // the invalid '\8' and '\9'
+ s.tokenFlags |= TokenFlagsContainsInvalidEscape
+ if flags&EscapeSequenceScanningFlagsReportInvalidEscapeErrors != 0 {
+ if flags&EscapeSequenceScanningFlagsRegularExpression != 0 && flags&EscapeSequenceScanningFlagsAtomEscape == 0 {
+ s.errorAt(diagnostics.Decimal_escape_sequences_and_backreferences_are_not_allowed_in_a_character_class, start, s.pos-start)
+ } else {
+ s.errorAt(diagnostics.Escape_sequence_0_is_not_allowed, start, s.pos-start, s.text[start:s.pos])
+ }
+ return string(rune(ch))
+ }
+ return s.text[start:s.pos]
+ case 'b':
+ return "\b"
+ case 't':
+ return "\t"
+ case 'n':
+ return "\n"
+ case 'v':
+ return "\v"
+ case 'f':
+ return "\f"
+ case 'r':
+ return "\r"
+ case '\'':
+ return "'"
+ case '"':
+ return "\""
+ case 'u':
+ // '\uDDDD' and '\U{DDDDDD}'
+ extended := s.char() == '{'
+ s.pos -= 2
+ codePoint := s.scanUnicodeEscape(flags&EscapeSequenceScanningFlagsReportInvalidEscapeErrors != 0)
+ if codePoint < 0 {
+ s.tokenFlags |= TokenFlagsContainsInvalidEscape
+ return s.text[start:s.pos]
+ }
+ if extended {
+ s.tokenFlags |= TokenFlagsExtendedUnicodeEscape
+ } else {
+ s.tokenFlags |= TokenFlagsUnicodeEscape
+ }
+ return string(codePoint)
+ case 'x':
+ // '\xDD'
+ for ; s.pos < start+4; s.pos++ {
+ if !isHexDigit(s.char()) {
+ s.tokenFlags |= TokenFlagsContainsInvalidEscape
+ if flags&EscapeSequenceScanningFlagsReportInvalidEscapeErrors != 0 {
+ s.error(diagnostics.Hexadecimal_digit_expected)
+ }
+ return s.text[start:s.pos]
+ }
+ }
+ s.tokenFlags |= TokenFlagsHexEscape
+ escapedValue, _ := strconv.ParseInt(s.text[start+2:s.pos], 16, 32)
+ return string(rune(escapedValue))
+ case '\r':
+ // when encountering a LineContinuation (i.e. a backslash and a line terminator sequence),
+ // the line terminator is interpreted to be "the empty code unit sequence".
+ if s.char() == '\n' {
+ s.pos++
+ }
+ fallthrough
+ case '\n':
+ // case CharacterCodes.lineSeparator !!!
+ // case CharacterCodes.paragraphSeparator !!!
+ return ""
+ default:
+ if flags&EscapeSequenceScanningFlagsAnyUnicodeMode != 0 || flags&EscapeSequenceScanningFlagsRegularExpression != 0 && flags&EscapeSequenceScanningFlagsAnnexB == 0 && isIdentifierPart(ch, s.languageVersion, LanguageVariantStandard) {
+ s.errorAt(diagnostics.This_character_cannot_be_escaped_in_a_regular_expression, s.pos-2, 2)
+ }
+ return string(rune(ch))
+ }
+}
+
+// Known to be at \u
+func (s *Scanner) scanUnicodeEscape(shouldEmitInvalidEscapeError bool) rune {
+ s.pos += 2
+ start := s.pos
+ extended := s.char() == '{'
+ var hexDigits string
+ if extended {
+ s.pos++
+ hexDigits = s.scanHexDigits(1, true, false)
+ } else {
+ hexDigits = s.scanHexDigits(4, false, false)
+ }
+ if hexDigits == "" {
+ if shouldEmitInvalidEscapeError {
+ s.error(diagnostics.Hexadecimal_digit_expected)
+ }
+ return -1
+ }
+ hexValue, _ := strconv.ParseInt(hexDigits, 16, 32)
+ if extended {
+ if hexValue > 0x10FFFF {
+ if shouldEmitInvalidEscapeError {
+ s.errorAt(diagnostics.An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive, start+1, s.pos-start-1)
+ }
+ return -1
+ }
+ if s.char() != '}' {
+ if shouldEmitInvalidEscapeError {
+ s.error(diagnostics.Unterminated_Unicode_escape_sequence)
+ }
+ return -1
+ }
+ s.pos++
+ }
+ return rune(hexValue)
+}
+
+// Current character is known to be a backslash. Check for Unicode escape of the form '\uXXXX'
+// or '\u{XXXXXX}' and return code point value if valid Unicode escape is found. Otherwise return -1.
+func (s *Scanner) peekUnicodeEscape() rune {
+ if s.charAt(1) == 'u' {
+ start := s.pos
+ codePoint := s.scanUnicodeEscape(false)
+ s.pos = start
+ return codePoint
+ }
+ return -1
+}
+
+func (s *Scanner) scanNumber() SyntaxKind {
+ start := s.pos
+ var fixedPart string
+ if s.char() == '0' {
+ s.pos++
+ if s.char() == '_' {
+ s.tokenFlags |= TokenFlagsContainsSeparator | TokenFlagsContainsInvalidSeparator
+ s.errorAt(diagnostics.Numeric_separators_are_not_allowed_here, s.pos, 1)
+ s.pos = start
+ fixedPart = s.scanNumberFragment()
+ } else {
+ digits, isOctal := s.scanDigits()
+ if digits == "" {
+ fixedPart = "0"
+ } else if !isOctal {
+ s.tokenFlags |= TokenFlagsContainsLeadingZero
+ fixedPart = digits
+ } else {
+ s.tokenFlags |= TokenFlagsOctal
+ s.tokenValue = "0o" + digits
+ s.errorAt(diagnostics.Octal_literals_are_not_allowed_Use_the_syntax_0, start, s.pos-start, digits)
+ return SyntaxKindNumericLiteral
+ }
+ }
+ } else {
+ fixedPart = s.scanNumberFragment()
+ }
+ fixedPartEnd := s.pos
+ fractionalPart := ""
+ exponentPreamble := ""
+ exponentPart := ""
+ bigIntSuffix := ""
+ if s.char() == '.' {
+ s.pos++
+ fractionalPart = s.scanNumberFragment()
+ }
+ end := s.pos
+ if s.char() == 'E' || s.char() == 'e' {
+ s.pos++
+ s.tokenFlags |= TokenFlagsScientific
+ if s.char() == '+' || s.char() == '-' {
+ s.pos++
+ }
+ startNumericPart := s.pos
+ exponentPart = s.scanNumberFragment()
+ if exponentPart == "" {
+ s.error(diagnostics.Digit_expected)
+ } else {
+ exponentPreamble = s.text[end:startNumericPart]
+ end = s.pos
+ }
+ } else if s.char() == 'n' {
+ bigIntSuffix = "n"
+ s.pos++
+ end = s.pos
+ }
+ if s.tokenFlags&TokenFlagsContainsSeparator != 0 {
+ s.tokenValue = fixedPart
+ if fractionalPart != "" {
+ s.tokenValue += "." + fractionalPart
+ }
+ if exponentPart != "" {
+ s.tokenValue += exponentPreamble + exponentPart
+ }
+ s.tokenValue += bigIntSuffix
+ } else {
+ s.tokenValue = s.text[start:end]
+ }
+ if s.tokenFlags&TokenFlagsContainsLeadingZero != 0 {
+ s.errorAt(diagnostics.Decimals_with_leading_zeros_are_not_allowed, start, s.pos-start)
+ return SyntaxKindNumericLiteral
+ }
+ ch, _ := s.charAndSize()
+ if isIdentifierStart(ch, s.languageVersion) {
+ idStart := s.pos
+ id := s.scanIdentifierParts()
+ if len(id) == 1 && s.text[idStart] == 'n' {
+ if s.tokenFlags&TokenFlagsScientific != 0 {
+ s.errorAt(diagnostics.A_bigint_literal_cannot_use_exponential_notation, start, s.pos-start)
+ } else if fixedPartEnd < idStart {
+ s.errorAt(diagnostics.A_bigint_literal_must_be_an_integer, start, s.pos-start)
+ } else {
+ s.errorAt(diagnostics.An_identifier_or_keyword_cannot_immediately_follow_a_numeric_literal, idStart, s.pos-idStart)
+ s.pos = idStart
+ }
+ }
+ }
+ if bigIntSuffix != "" {
+ return SyntaxKindBigintLiteral
+ }
+ return SyntaxKindNumericLiteral
+}
+
+func (s *Scanner) scanNumberFragment() string {
+ start := s.pos
+ allowSeparator := false
+ isPreviousTokenSeparator := false
+ result := ""
+ for {
+ ch := s.char()
+ if ch == '_' {
+ s.tokenFlags |= TokenFlagsContainsSeparator
+ if allowSeparator {
+ allowSeparator = false
+ isPreviousTokenSeparator = true
+ result += s.text[start:s.pos]
+ } else {
+ s.tokenFlags |= TokenFlagsContainsInvalidSeparator
+ if isPreviousTokenSeparator {
+ s.errorAt(diagnostics.Multiple_consecutive_numeric_separators_are_not_permitted, s.pos, 1)
+ } else {
+ s.errorAt(diagnostics.Numeric_separators_are_not_allowed_here, s.pos, 1)
+ }
+ }
+ s.pos++
+ start = s.pos
+ continue
+ }
+ if isDigit(ch) {
+ allowSeparator = true
+ isPreviousTokenSeparator = false
+ s.pos++
+ continue
+ }
+ break
+ }
+ if isPreviousTokenSeparator {
+ s.tokenFlags |= TokenFlagsContainsInvalidSeparator
+ s.errorAt(diagnostics.Numeric_separators_are_not_allowed_here, s.pos-1, 1)
+ }
+ return result + s.text[start:s.pos]
+}
+
+func (s *Scanner) scanDigits() (string, bool) {
+ start := s.pos
+ isOctal := true
+ for isDigit(s.char()) {
+ if !isOctalDigit(s.char()) {
+ isOctal = false
+ }
+ s.pos++
+ }
+ return s.text[start:s.pos], isOctal
+}
+
+func (s *Scanner) scanHexDigits(minCount int, scanAsManyAsPossible bool, canHaveSeparators bool) string {
+ result := ""
+ allowSeparator := false
+ isPreviousTokenSeparator := false
+ for len(result) < minCount || scanAsManyAsPossible {
+ ch := s.char()
+ if isHexDigit(ch) {
+ if ch >= 'A' && ch <= 'F' {
+ ch += 'a' - 'A' // standardize hex literals to lowercase
+ }
+ result += string(ch)
+ allowSeparator = canHaveSeparators
+ isPreviousTokenSeparator = false
+ } else if canHaveSeparators && ch == '_' {
+ s.tokenFlags |= TokenFlagsContainsSeparator
+ if allowSeparator {
+ allowSeparator = false
+ isPreviousTokenSeparator = true
+ } else if isPreviousTokenSeparator {
+ s.errorAt(diagnostics.Multiple_consecutive_numeric_separators_are_not_permitted, s.pos, 1)
+ } else {
+ s.errorAt(diagnostics.Numeric_separators_are_not_allowed_here, s.pos, 1)
+ }
+ } else {
+ break
+ }
+ s.pos++
+ }
+ if isPreviousTokenSeparator {
+ s.errorAt(diagnostics.Numeric_separators_are_not_allowed_here, s.pos-1, 1)
+ }
+ if len(result) < minCount {
+ result = ""
+ }
+ return result
+}
+
+func (s *Scanner) scanBinaryOrOctalDigits(base int32) string {
+ result := ""
+ allowSeparator := false
+ isPreviousTokenSeparator := false
+ for {
+ ch := s.char()
+ if isDigit(ch) && ch-'0' < base {
+ result += string(ch)
+ allowSeparator = true
+ isPreviousTokenSeparator = false
+ } else if ch == '_' {
+ s.tokenFlags |= TokenFlagsContainsSeparator
+ if allowSeparator {
+ allowSeparator = false
+ isPreviousTokenSeparator = true
+ } else if isPreviousTokenSeparator {
+ s.errorAt(diagnostics.Multiple_consecutive_numeric_separators_are_not_permitted, s.pos, 1)
+ } else {
+ s.errorAt(diagnostics.Numeric_separators_are_not_allowed_here, s.pos, 1)
+ }
+ } else {
+ break
+ }
+ s.pos++
+ }
+ if isPreviousTokenSeparator {
+ s.errorAt(diagnostics.Numeric_separators_are_not_allowed_here, s.pos-1, 1)
+ }
+ return result
+}
+
+func (s *Scanner) scanBigIntSuffix() SyntaxKind {
+ if s.char() == 'n' {
+ s.pos++
+ return SyntaxKindBigintLiteral
+ }
+ return SyntaxKindNumericLiteral
+}
+
+func (s *Scanner) scanInvalidCharacter() {
+ _, size := s.charAndSize()
+ s.errorAt(diagnostics.Invalid_character, s.pos, size)
+ s.pos += size
+ s.token = SyntaxKindUnknown
+}
+
+func getIdentifierToken(str string) SyntaxKind {
+ if len(str) >= 2 && len(str) <= 12 && str[0] >= 'a' && str[0] <= 'z' {
+ keyword := textToKeyword[str]
+ if keyword != SyntaxKindUnknown {
+ return keyword
+ }
+ }
+ return SyntaxKindIdentifier
+}
+
+func isWhiteSpaceLike(ch rune) bool {
+ return isWhiteSpaceSingleLine(ch) || isLineBreak(ch)
+}
+
+func isWhiteSpaceSingleLine(ch rune) bool {
+ // Note: nextLine is in the Zs space, and should be considered to be a whitespace.
+ // It is explicitly not a line-break as it isn't in the exact set specified by EcmaScript.
+ switch ch {
+ case
+ ' ', // space
+ '\t', // tab
+ '\v', // verticalTab
+ '\f', // formFeed
+ 0x0085, // nextLine
+ 0x00A0, // nonBreakingSpace
+ 0x1680, // ogham
+ 0x2000, // enQuad
+ 0x2001, // emQuad
+ 0x2002, // enSpace
+ 0x2003, // emSpace
+ 0x2004, // threePerEmSpace
+ 0x2005, // fourPerEmSpace
+ 0x2006, // sixPerEmSpace
+ 0x2007, // figureSpace
+ 0x2008, // punctuationEmSpace
+ 0x2009, // thinSpace
+ 0x200A, // hairSpace
+ 0x200B, // zeroWidthSpace
+ 0x202F, // narrowNoBreakSpace
+ 0x205F, // mathematicalSpace
+ 0x3000, // ideographicSpace
+ 0xFEFF: // byteOrderMark
+ return true
+ }
+ return false
+}
+
+func isLineBreak(ch rune) bool {
+ // ES5 7.3:
+ // The ECMAScript line terminator characters are listed in Table 3.
+ // Table 3: Line Terminator Characters
+ // Code Unit Value Name Formal Name
+ // \u000A Line Feed
+ // \u000D Carriage Return
+ // \u2028 Line separator
+ // \u2029 Paragraph separator
+ // Only the characters in Table 3 are treated as line terminators. Other new line or line
+ // breaking characters are treated as white space but not as line terminators.
+ switch ch {
+ case
+ '\n', // lineFeed
+ '\r', // carriageReturn
+ 0x2028, // lineSeparator
+ 0x2029: // paragraphSeparator
+ return true
+ }
+ return false
+}
+
+func isDigit(ch rune) bool {
+ return ch >= '0' && ch <= '9'
+}
+
+func isOctalDigit(ch rune) bool {
+ return ch >= '0' && ch <= '7'
+}
+
+func isHexDigit(ch rune) bool {
+ return ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'F' || ch >= 'a' && ch <= 'f'
+}
+
+func isASCIILetter(ch rune) bool {
+ return ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z'
+}
+
+// Section 6.1.4
+func isWordCharacter(ch rune) bool {
+ return isASCIILetter(ch) || isDigit(ch) || ch == '_'
+}
+
+func isIdentifierStart(ch rune, languageVersion ScriptTarget) bool {
+ return isASCIILetter(ch) || ch == '_' || ch == '$' || ch > 0x7F && isUnicodeIdentifierStart(ch, languageVersion)
+}
+
+func isIdentifierPart(ch rune, languageVersion ScriptTarget, identifierVariant LanguageVariant) bool {
+ return isWordCharacter(ch) || ch == '$' ||
+ // "-" and ":" are valid in JSX Identifiers
+ identifierVariant == LanguageVariantJSX && (ch == '-' || ch == ':') ||
+ ch > 0x7F && isUnicodeIdentifierPart(ch, languageVersion)
+}
+
+func isUnicodeIdentifierStart(ch rune, languageVersion ScriptTarget) bool {
+ return isInUnicodeRanges(ch, ifElse(languageVersion >= ScriptTargetES2015, unicodeESNextIdentifierStart, unicodeES5IdentifierStart))
+}
+
+func isUnicodeIdentifierPart(ch rune, languageVersion ScriptTarget) bool {
+ return isInUnicodeRanges(ch, ifElse(languageVersion >= ScriptTargetES2015, unicodeESNextIdentifierPart, unicodeES5IdentifierPart))
+}
+
+func isInUnicodeRanges(cp rune, ranges []rune) bool {
+ // Bail out quickly if it couldn't possibly be in the map
+ if cp < ranges[0] {
+ return false
+ }
+ // Perform binary search in one of the Unicode range maps
+ lo := 0
+ hi := len(ranges)
+ for lo+1 < hi {
+ mid := lo + (hi-lo)/2
+ // mid has to be even to catch beginning of a range
+ mid -= mid % 2
+ if ranges[mid] <= cp && cp <= ranges[mid+1] {
+ return true
+ }
+ if cp < ranges[mid] {
+ hi = mid
+ } else {
+ lo = mid + 2
+ }
+ }
+ return false
+}
+
+var tokenToText map[SyntaxKind]string
+
+func init() {
+ tokenToText = make(map[SyntaxKind]string, len(textToKeyword)+len(textToToken))
+ for text, key := range textToKeyword {
+ tokenToText[key] = text
+ }
+ for text, key := range textToToken {
+ tokenToText[key] = text
+ }
+}
+
+func TokenToString(token SyntaxKind) string {
+ return tokenToText[token]
+}
+
+// !!! Should just skip trivia
+func skipTrivia(sourceText string, pos int) int {
+ s := NewScanner()
+ s.text = sourceText
+ s.pos = pos
+ s.Scan()
+ return s.tokenStart
+}
+
+func getScannerForSourceFile(sourceFile *SourceFile, pos int) *Scanner {
+ s := NewScanner()
+ s.text = sourceFile.text
+ s.pos = pos
+ s.languageVersion = sourceFile.languageVersion
+ s.languageVariant = sourceFile.languageVariant
+ s.Scan()
+ return s
+}
+
+func getRangeOfTokenAtPosition(sourceFile *SourceFile, pos int) TextRange {
+ s := getScannerForSourceFile(sourceFile, pos)
+ return NewTextRange(s.tokenStart, s.pos)
+}
+
+func computeLineStarts(text string) []TextPos {
+ var result []TextPos
+ pos := 0
+ lineStart := 0
+ for pos < len(text) {
+ b := text[pos]
+ if b < 0x7F {
+ pos++
+ switch b {
+ case '\r':
+ if pos < len(text) && text[pos] == '\n' {
+ pos++
+ }
+ fallthrough
+ case '\n':
+ result = append(result, TextPos(lineStart))
+ lineStart = pos
+ }
+ } else {
+ ch, size := utf8.DecodeRuneInString(text[pos:])
+ pos += size
+ if isLineBreak(ch) {
+ result = append(result, TextPos(lineStart))
+ lineStart = pos
+ }
+ }
+ }
+ result = append(result, TextPos(lineStart))
+ return result
+}
+
+func computeLineOfPosition(lineStarts []TextPos, pos TextPos) int {
+ low := 0
+ high := len(lineStarts) - 1
+ for low <= high {
+ middle := low + ((high - low) >> 1)
+ value := lineStarts[middle]
+ if value < pos {
+ low = middle + 1
+ } else if value > pos {
+ high = middle - 1
+ } else {
+ return middle
+ }
+ }
+ return low - 1
+}
+
+func getLineStarts(sourceFile *SourceFile) []TextPos {
+ if sourceFile.lineMap == nil {
+ sourceFile.lineMap = computeLineStarts(sourceFile.text)
+ }
+ return sourceFile.lineMap
+}
+
+func GetLineAndCharacterOfPosition(sourceFile *SourceFile, pos int) (line int, character int) {
+ line = computeLineOfPosition(getLineStarts(sourceFile), TextPos(pos))
+ character = utf8.RuneCountInString(sourceFile.text[sourceFile.lineMap[line]:pos])
+ return
+}
+
+func getEndLinePosition(sourceFile *SourceFile, line int) int {
+ pos := int(getLineStarts(sourceFile)[line])
+ for {
+ ch, size := utf8.DecodeRuneInString(sourceFile.text[pos:])
+ if size == 0 || isLineBreak(ch) {
+ return pos
+ }
+ pos += size
+ }
+}
diff --git a/internal/compiler/types.go b/internal/compiler/types.go
new file mode 100644
index 0000000000..9f65e56625
--- /dev/null
+++ b/internal/compiler/types.go
@@ -0,0 +1,1487 @@
+package compiler
+
+type SyntaxKind int16
+
+const (
+ SyntaxKindUnknown SyntaxKind = iota
+ SyntaxKindEndOfFile
+ SyntaxKindConflictMarkerTrivia
+ SyntaxKindNonTextFileMarkerTrivia
+ SyntaxKindNumericLiteral
+ SyntaxKindBigintLiteral
+ SyntaxKindStringLiteral
+ SyntaxKindJsxText
+ SyntaxKindJsxTextAllWhiteSpaces
+ SyntaxKindRegularExpressionLiteral
+ SyntaxKindNoSubstitutionTemplateLiteral
+ // Pseudo-literals
+ SyntaxKindTemplateHead
+ SyntaxKindTemplateMiddle
+ SyntaxKindTemplateTail
+ // Punctuation
+ SyntaxKindOpenBraceToken
+ SyntaxKindCloseBraceToken
+ SyntaxKindOpenParenToken
+ SyntaxKindCloseParenToken
+ SyntaxKindOpenBracketToken
+ SyntaxKindCloseBracketToken
+ SyntaxKindDotToken
+ SyntaxKindDotDotDotToken
+ SyntaxKindSemicolonToken
+ SyntaxKindCommaToken
+ SyntaxKindQuestionDotToken
+ SyntaxKindLessThanToken
+ SyntaxKindLessThanSlashToken
+ SyntaxKindGreaterThanToken
+ SyntaxKindLessThanEqualsToken
+ SyntaxKindGreaterThanEqualsToken
+ SyntaxKindEqualsEqualsToken
+ SyntaxKindExclamationEqualsToken
+ SyntaxKindEqualsEqualsEqualsToken
+ SyntaxKindExclamationEqualsEqualsToken
+ SyntaxKindEqualsGreaterThanToken
+ SyntaxKindPlusToken
+ SyntaxKindMinusToken
+ SyntaxKindAsteriskToken
+ SyntaxKindAsteriskAsteriskToken
+ SyntaxKindSlashToken
+ SyntaxKindPercentToken
+ SyntaxKindPlusPlusToken
+ SyntaxKindMinusMinusToken
+ SyntaxKindLessThanLessThanToken
+ SyntaxKindGreaterThanGreaterThanToken
+ SyntaxKindGreaterThanGreaterThanGreaterThanToken
+ SyntaxKindAmpersandToken
+ SyntaxKindBarToken
+ SyntaxKindCaretToken
+ SyntaxKindExclamationToken
+ SyntaxKindTildeToken
+ SyntaxKindAmpersandAmpersandToken
+ SyntaxKindBarBarToken
+ SyntaxKindQuestionToken
+ SyntaxKindColonToken
+ SyntaxKindAtToken
+ SyntaxKindQuestionQuestionToken
+ /** Only the JSDoc scanner produces BacktickToken. The normal scanner produces NoSubstitutionTemplateLiteral and related kinds. */
+ SyntaxKindBacktickToken
+ /** Only the JSDoc scanner produces HashToken. The normal scanner produces PrivateIdentifier. */
+ SyntaxKindHashToken
+ // Assignments
+ SyntaxKindEqualsToken
+ SyntaxKindPlusEqualsToken
+ SyntaxKindMinusEqualsToken
+ SyntaxKindAsteriskEqualsToken
+ SyntaxKindAsteriskAsteriskEqualsToken
+ SyntaxKindSlashEqualsToken
+ SyntaxKindPercentEqualsToken
+ SyntaxKindLessThanLessThanEqualsToken
+ SyntaxKindGreaterThanGreaterThanEqualsToken
+ SyntaxKindGreaterThanGreaterThanGreaterThanEqualsToken
+ SyntaxKindAmpersandEqualsToken
+ SyntaxKindBarEqualsToken
+ SyntaxKindBarBarEqualsToken
+ SyntaxKindAmpersandAmpersandEqualsToken
+ SyntaxKindQuestionQuestionEqualsToken
+ SyntaxKindCaretEqualsToken
+ // Identifiers and PrivateIdentifier
+ SyntaxKindIdentifier
+ SyntaxKindPrivateIdentifier
+ SyntaxKindJSDocCommentTextToken
+ // Reserved words
+ SyntaxKindBreakKeyword
+ SyntaxKindCaseKeyword
+ SyntaxKindCatchKeyword
+ SyntaxKindClassKeyword
+ SyntaxKindConstKeyword
+ SyntaxKindContinueKeyword
+ SyntaxKindDebuggerKeyword
+ SyntaxKindDefaultKeyword
+ SyntaxKindDeleteKeyword
+ SyntaxKindDoKeyword
+ SyntaxKindElseKeyword
+ SyntaxKindEnumKeyword
+ SyntaxKindExportKeyword
+ SyntaxKindExtendsKeyword
+ SyntaxKindFalseKeyword
+ SyntaxKindFinallyKeyword
+ SyntaxKindForKeyword
+ SyntaxKindFunctionKeyword
+ SyntaxKindIfKeyword
+ SyntaxKindImportKeyword
+ SyntaxKindInKeyword
+ SyntaxKindInstanceOfKeyword
+ SyntaxKindNewKeyword
+ SyntaxKindNullKeyword
+ SyntaxKindReturnKeyword
+ SyntaxKindSuperKeyword
+ SyntaxKindSwitchKeyword
+ SyntaxKindThisKeyword
+ SyntaxKindThrowKeyword
+ SyntaxKindTrueKeyword
+ SyntaxKindTryKeyword
+ SyntaxKindTypeOfKeyword
+ SyntaxKindVarKeyword
+ SyntaxKindVoidKeyword
+ SyntaxKindWhileKeyword
+ SyntaxKindWithKeyword
+ // Strict mode reserved words
+ SyntaxKindImplementsKeyword
+ SyntaxKindInterfaceKeyword
+ SyntaxKindLetKeyword
+ SyntaxKindPackageKeyword
+ SyntaxKindPrivateKeyword
+ SyntaxKindProtectedKeyword
+ SyntaxKindPublicKeyword
+ SyntaxKindStaticKeyword
+ SyntaxKindYieldKeyword
+ // Contextual keywords
+ SyntaxKindAbstractKeyword
+ SyntaxKindAccessorKeyword
+ SyntaxKindAsKeyword
+ SyntaxKindAssertsKeyword
+ SyntaxKindAssertKeyword
+ SyntaxKindAnyKeyword
+ SyntaxKindAsyncKeyword
+ SyntaxKindAwaitKeyword
+ SyntaxKindBooleanKeyword
+ SyntaxKindConstructorKeyword
+ SyntaxKindDeclareKeyword
+ SyntaxKindGetKeyword
+ SyntaxKindImmediateKeyword
+ SyntaxKindInferKeyword
+ SyntaxKindIntrinsicKeyword
+ SyntaxKindIsKeyword
+ SyntaxKindKeyOfKeyword
+ SyntaxKindModuleKeyword
+ SyntaxKindNamespaceKeyword
+ SyntaxKindNeverKeyword
+ SyntaxKindOutKeyword
+ SyntaxKindReadonlyKeyword
+ SyntaxKindRequireKeyword
+ SyntaxKindNumberKeyword
+ SyntaxKindObjectKeyword
+ SyntaxKindSatisfiesKeyword
+ SyntaxKindSetKeyword
+ SyntaxKindStringKeyword
+ SyntaxKindSymbolKeyword
+ SyntaxKindTypeKeyword
+ SyntaxKindUndefinedKeyword
+ SyntaxKindUniqueKeyword
+ SyntaxKindUnknownKeyword
+ SyntaxKindUsingKeyword
+ SyntaxKindFromKeyword
+ SyntaxKindGlobalKeyword
+ SyntaxKindBigIntKeyword
+ SyntaxKindOverrideKeyword
+ SyntaxKindOfKeyword // LastKeyword and LastToken and LastContextualKeyword
+ // Parse tree nodes
+ // Names
+ SyntaxKindQualifiedName
+ SyntaxKindComputedPropertyName
+ // Lists
+ SyntaxKindModifierList
+ SyntaxKindTypeParameterList
+ SyntaxKindTypeArgumentList
+ // Signature elements
+ SyntaxKindTypeParameter
+ SyntaxKindParameter
+ SyntaxKindDecorator
+ // TypeMember
+ SyntaxKindPropertySignature
+ SyntaxKindPropertyDeclaration
+ SyntaxKindMethodSignature
+ SyntaxKindMethodDeclaration
+ SyntaxKindClassStaticBlockDeclaration
+ SyntaxKindConstructor
+ SyntaxKindGetAccessor
+ SyntaxKindSetAccessor
+ SyntaxKindCallSignature
+ SyntaxKindConstructSignature
+ SyntaxKindIndexSignature
+ // Type
+ SyntaxKindTypePredicate
+ SyntaxKindTypeReference
+ SyntaxKindFunctionType
+ SyntaxKindConstructorType
+ SyntaxKindTypeQuery
+ SyntaxKindTypeLiteral
+ SyntaxKindArrayType
+ SyntaxKindTupleType
+ SyntaxKindOptionalType
+ SyntaxKindRestType
+ SyntaxKindUnionType
+ SyntaxKindIntersectionType
+ SyntaxKindConditionalType
+ SyntaxKindInferType
+ SyntaxKindParenthesizedType
+ SyntaxKindThisType
+ SyntaxKindTypeOperator
+ SyntaxKindIndexedAccessType
+ SyntaxKindMappedType
+ SyntaxKindLiteralType
+ SyntaxKindNamedTupleMember
+ SyntaxKindTemplateLiteralType
+ SyntaxKindTemplateLiteralTypeSpan
+ SyntaxKindImportType
+ // Binding patterns
+ SyntaxKindObjectBindingPattern
+ SyntaxKindArrayBindingPattern
+ SyntaxKindBindingElement
+ // Expression
+ SyntaxKindArrayLiteralExpression
+ SyntaxKindObjectLiteralExpression
+ SyntaxKindPropertyAccessExpression
+ SyntaxKindElementAccessExpression
+ SyntaxKindCallExpression
+ SyntaxKindNewExpression
+ SyntaxKindTaggedTemplateExpression
+ SyntaxKindTypeAssertionExpression
+ SyntaxKindParenthesizedExpression
+ SyntaxKindFunctionExpression
+ SyntaxKindArrowFunction
+ SyntaxKindDeleteExpression
+ SyntaxKindTypeOfExpression
+ SyntaxKindVoidExpression
+ SyntaxKindAwaitExpression
+ SyntaxKindPrefixUnaryExpression
+ SyntaxKindPostfixUnaryExpression
+ SyntaxKindBinaryExpression
+ SyntaxKindConditionalExpression
+ SyntaxKindTemplateExpression
+ SyntaxKindYieldExpression
+ SyntaxKindSpreadElement
+ SyntaxKindClassExpression
+ SyntaxKindOmittedExpression
+ SyntaxKindExpressionWithTypeArguments
+ SyntaxKindAsExpression
+ SyntaxKindNonNullExpression
+ SyntaxKindMetaProperty
+ SyntaxKindSyntheticExpression
+ SyntaxKindSatisfiesExpression
+ // Misc
+ SyntaxKindTemplateSpan
+ SyntaxKindSemicolonClassElement
+ // Element
+ SyntaxKindBlock
+ SyntaxKindEmptyStatement
+ SyntaxKindVariableStatement
+ SyntaxKindExpressionStatement
+ SyntaxKindIfStatement
+ SyntaxKindDoStatement
+ SyntaxKindWhileStatement
+ SyntaxKindForStatement
+ SyntaxKindForInStatement
+ SyntaxKindForOfStatement
+ SyntaxKindContinueStatement
+ SyntaxKindBreakStatement
+ SyntaxKindReturnStatement
+ SyntaxKindWithStatement
+ SyntaxKindSwitchStatement
+ SyntaxKindLabeledStatement
+ SyntaxKindThrowStatement
+ SyntaxKindTryStatement
+ SyntaxKindDebuggerStatement
+ SyntaxKindVariableDeclaration
+ SyntaxKindVariableDeclarationList
+ SyntaxKindFunctionDeclaration
+ SyntaxKindClassDeclaration
+ SyntaxKindInterfaceDeclaration
+ SyntaxKindTypeAliasDeclaration
+ SyntaxKindEnumDeclaration
+ SyntaxKindModuleDeclaration
+ SyntaxKindModuleBlock
+ SyntaxKindCaseBlock
+ SyntaxKindNamespaceExportDeclaration
+ SyntaxKindImportEqualsDeclaration
+ SyntaxKindImportDeclaration
+ SyntaxKindImportClause
+ SyntaxKindNamespaceImport
+ SyntaxKindNamedImports
+ SyntaxKindImportSpecifier
+ SyntaxKindExportAssignment
+ SyntaxKindExportDeclaration
+ SyntaxKindNamedExports
+ SyntaxKindNamespaceExport
+ SyntaxKindExportSpecifier
+ SyntaxKindMissingDeclaration
+ // Module references
+ SyntaxKindExternalModuleReference
+ // JSX
+ SyntaxKindJsxElement
+ SyntaxKindJsxSelfClosingElement
+ SyntaxKindJsxOpeningElement
+ SyntaxKindJsxClosingElement
+ SyntaxKindJsxFragment
+ SyntaxKindJsxOpeningFragment
+ SyntaxKindJsxClosingFragment
+ SyntaxKindJsxAttribute
+ SyntaxKindJsxAttributes
+ SyntaxKindJsxSpreadAttribute
+ SyntaxKindJsxExpression
+ SyntaxKindJsxNamespacedName
+ // Clauses
+ SyntaxKindCaseClause
+ SyntaxKindDefaultClause
+ SyntaxKindHeritageClause
+ SyntaxKindCatchClause
+ // Import attributes
+ SyntaxKindImportAttributes
+ SyntaxKindImportAttribute
+ // Property assignments
+ SyntaxKindPropertyAssignment
+ SyntaxKindShorthandPropertyAssignment
+ SyntaxKindSpreadAssignment
+ // Enum
+ SyntaxKindEnumMember
+ // Top-level nodes
+ SyntaxKindSourceFile
+ SyntaxKindBundle
+ // JSDoc nodes
+ SyntaxKindJSDocTypeExpression
+ SyntaxKindJSDocNameReference
+ SyntaxKindJSDocMemberName // C#p
+ SyntaxKindJSDocAllType // The * type
+ SyntaxKindJSDocUnknownType // The ? type
+ SyntaxKindJSDocNullableType
+ SyntaxKindJSDocNonNullableType
+ SyntaxKindJSDocOptionalType
+ SyntaxKindJSDocFunctionType
+ SyntaxKindJSDocVariadicType
+ SyntaxKindJSDocNamepathType // https://jsdoc.app/about-namepaths.html
+ SyntaxKindJSDoc
+ SyntaxKindJSDocText
+ SyntaxKindJSDocTypeLiteral
+ SyntaxKindJSDocSignature
+ SyntaxKindJSDocLink
+ SyntaxKindJSDocLinkCode
+ SyntaxKindJSDocLinkPlain
+ SyntaxKindJSDocTag
+ SyntaxKindJSDocAugmentsTag
+ SyntaxKindJSDocImplementsTag
+ SyntaxKindJSDocAuthorTag
+ SyntaxKindJSDocDeprecatedTag
+ SyntaxKindJSDocImmediateTag
+ SyntaxKindJSDocClassTag
+ SyntaxKindJSDocPublicTag
+ SyntaxKindJSDocPrivateTag
+ SyntaxKindJSDocProtectedTag
+ SyntaxKindJSDocReadonlyTag
+ SyntaxKindJSDocOverrideTag
+ SyntaxKindJSDocCallbackTag
+ SyntaxKindJSDocOverloadTag
+ SyntaxKindJSDocEnumTag
+ SyntaxKindJSDocParameterTag
+ SyntaxKindJSDocReturnTag
+ SyntaxKindJSDocThisTag
+ SyntaxKindJSDocTypeTag
+ SyntaxKindJSDocTemplateTag
+ SyntaxKindJSDocTypedefTag
+ SyntaxKindJSDocSeeTag
+ SyntaxKindJSDocPropertyTag
+ SyntaxKindJSDocThrowsTag
+ SyntaxKindJSDocSatisfiesTag
+ SyntaxKindJSDocImportTag
+ // Synthesized list
+ SyntaxKindSyntaxList
+ // Transformation nodes
+ SyntaxKindNotEmittedStatement
+ SyntaxKindPartiallyEmittedExpression
+ SyntaxKindCommaListExpression
+ SyntaxKindSyntheticReferenceExpression
+ // Enum value count
+ SyntaxKindCount
+ // Markers
+ SyntaxKindFirstAssignment = SyntaxKindEqualsToken
+ SyntaxKindLastAssignment = SyntaxKindCaretEqualsToken
+ SyntaxKindFirstCompoundAssignment = SyntaxKindPlusEqualsToken
+ SyntaxKindLastCompoundAssignment = SyntaxKindCaretEqualsToken
+ SyntaxKindFirstReservedWord = SyntaxKindBreakKeyword
+ SyntaxKindLastReservedWord = SyntaxKindWithKeyword
+ SyntaxKindFirstKeyword = SyntaxKindBreakKeyword
+ SyntaxKindLastKeyword = SyntaxKindOfKeyword
+ SyntaxKindFirstFutureReservedWord = SyntaxKindImplementsKeyword
+ SyntaxKindLastFutureReservedWord = SyntaxKindYieldKeyword
+ SyntaxKindFirstTypeNode = SyntaxKindTypePredicate
+ SyntaxKindLastTypeNode = SyntaxKindImportType
+ SyntaxKindFirstPunctuation = SyntaxKindOpenBraceToken
+ SyntaxKindLastPunctuation = SyntaxKindCaretEqualsToken
+ SyntaxKindFirstToken = SyntaxKindUnknown
+ SyntaxKindLastToken = SyntaxKindLastKeyword
+ SyntaxKindFirstLiteralToken = SyntaxKindNumericLiteral
+ SyntaxKindLastLiteralToken = SyntaxKindNoSubstitutionTemplateLiteral
+ SyntaxKindFirstTemplateToken = SyntaxKindNoSubstitutionTemplateLiteral
+ SyntaxKindLastTemplateToken = SyntaxKindTemplateTail
+ SyntaxKindFirstBinaryOperator = SyntaxKindLessThanToken
+ SyntaxKindLastBinaryOperator = SyntaxKindCaretEqualsToken
+ SyntaxKindFirstStatement = SyntaxKindVariableStatement
+ SyntaxKindLastStatement = SyntaxKindDebuggerStatement
+ SyntaxKindFirstNode = SyntaxKindQualifiedName
+ SyntaxKindFirstJSDocNode = SyntaxKindJSDocTypeExpression
+ SyntaxKindLastJSDocNode = SyntaxKindJSDocImportTag
+ SyntaxKindFirstJSDocTagNode = SyntaxKindJSDocTag
+ SyntaxKindLastJSDocTagNode = SyntaxKindJSDocImportTag
+ SyntaxKindFirstContextualKeyword = SyntaxKindAbstractKeyword
+ SyntaxKindLastContextualKeyword = SyntaxKindOfKeyword
+)
+
+type NodeFlags uint32
+
+const (
+ NodeFlagsNone NodeFlags = 0
+ NodeFlagsLet NodeFlags = 1 << 0 // Variable declaration
+ NodeFlagsConst NodeFlags = 1 << 1 // Variable declaration
+ NodeFlagsUsing NodeFlags = 1 << 2 // Variable declaration
+ NodeFlagsNestedNamespace NodeFlags = 1 << 3 // Namespace declaration
+ NodeFlagsSynthesized NodeFlags = 1 << 4 // Node was synthesized during transformation
+ NodeFlagsNamespace NodeFlags = 1 << 5 // Namespace declaration
+ NodeFlagsOptionalChain NodeFlags = 1 << 6 // Chained MemberExpression rooted to a pseudo-OptionalExpression
+ NodeFlagsExportContext NodeFlags = 1 << 7 // Export context (initialized by binding)
+ NodeFlagsContainsThis NodeFlags = 1 << 8 // Interface contains references to "this"
+ NodeFlagsHasImplicitReturn NodeFlags = 1 << 9 // If function implicitly returns on one of codepaths (initialized by binding)
+ NodeFlagsHasExplicitReturn NodeFlags = 1 << 10 // If function has explicit reachable return on one of codepaths (initialized by binding)
+ NodeFlagsGlobalAugmentation NodeFlags = 1 << 11 // Set if module declaration is an augmentation for the global scope
+ NodeFlagsHasAsyncFunctions NodeFlags = 1 << 12 // If the file has async functions (initialized by binding)
+ NodeFlagsDisallowInContext NodeFlags = 1 << 13 // If node was parsed in a context where 'in-expressions' are not allowed
+ NodeFlagsYieldContext NodeFlags = 1 << 14 // If node was parsed in the 'yield' context created when parsing a generator
+ NodeFlagsDecoratorContext NodeFlags = 1 << 15 // If node was parsed as part of a decorator
+ NodeFlagsAwaitContext NodeFlags = 1 << 16 // If node was parsed in the 'await' context created when parsing an async function
+ NodeFlagsDisallowConditionalTypesContext NodeFlags = 1 << 17 // If node was parsed in a context where conditional types are not allowed
+ NodeFlagsThisNodeHasError NodeFlags = 1 << 18 // If the parser encountered an error when parsing the code that created this node
+ NodeFlagsJavaScriptFile NodeFlags = 1 << 19 // If node was parsed in a JavaScript
+ NodeFlagsThisNodeOrAnySubNodesHasError NodeFlags = 1 << 20 // If this node or any of its children had an error
+ NodeFlagsHasAggregatedChildData NodeFlags = 1 << 21 // If we've computed data from children and cached it in this node
+
+ // These flags will be set when the parser encounters a dynamic import expression or 'import.meta' to avoid
+ // walking the tree if the flags are not set. However, these flags are just a approximation
+ // (hence why it's named "PossiblyContainsDynamicImport") because once set, the flags never get cleared.
+ // During editing, if a dynamic import is removed, incremental parsing will *NOT* clear this flag.
+ // This means that the tree will always be traversed during module resolution, or when looking for external module indicators.
+ // However, the removal operation should not occur often and in the case of the
+ // removal, it is likely that users will add the import anyway.
+ // The advantage of this approach is its simplicity. For the case of batch compilation,
+ // we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used.
+ NodeFlagsPossiblyContainsDynamicImport NodeFlags = 1 << 22
+ NodeFlagsPossiblyContainsImportMeta NodeFlags = 1 << 23
+
+ NodeFlagsJSDoc NodeFlags = 1 << 24 // If node was parsed inside jsdoc
+ NodeFlagsAmbient NodeFlags = 1 << 25 // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier.
+ NodeFlagsInWithStatement NodeFlags = 1 << 26 // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
+ NodeFlagsJsonFile NodeFlags = 1 << 27 // If node was parsed in a Json
+ NodeFlagsTypeCached NodeFlags = 1 << 28 // If a type was cached for node at any point
+ NodeFlagsDeprecated NodeFlags = 1 << 29 // If has '@deprecated' JSDoc tag
+
+ NodeFlagsBlockScoped = NodeFlagsLet | NodeFlagsConst | NodeFlagsUsing
+ NodeFlagsConstant = NodeFlagsConst | NodeFlagsUsing
+ NodeFlagsAwaitUsing = NodeFlagsConst | NodeFlagsUsing // Variable declaration (NOTE: on a single node these flags would otherwise be mutually exclusive)
+
+ NodeFlagsReachabilityCheckFlags = NodeFlagsHasImplicitReturn | NodeFlagsHasExplicitReturn
+ NodeFlagsReachabilityAndEmitFlags = NodeFlagsReachabilityCheckFlags | NodeFlagsHasAsyncFunctions
+
+ // Parsing context flags
+ NodeFlagsContextFlags NodeFlags = NodeFlagsDisallowInContext | NodeFlagsDisallowConditionalTypesContext | NodeFlagsYieldContext | NodeFlagsDecoratorContext | NodeFlagsAwaitContext | NodeFlagsJavaScriptFile | NodeFlagsInWithStatement | NodeFlagsAmbient
+
+ // Exclude these flags when parsing a Type
+ NodeFlagsTypeExcludesFlags NodeFlags = NodeFlagsYieldContext | NodeFlagsAwaitContext
+
+ // Represents all flags that are potentially set once and
+ // never cleared on SourceFiles which get re-used in between incremental parses.
+ // See the comment above on `PossiblyContainsDynamicImport` and `PossiblyContainsImportMeta`.
+ NodeFlagsPermanentlySetIncrementalFlags NodeFlags = NodeFlagsPossiblyContainsDynamicImport | NodeFlagsPossiblyContainsImportMeta
+
+ // The following flags repurpose other NodeFlags as different meanings for Identifier nodes
+ NodeFlagsIdentifierHasExtendedUnicodeEscape NodeFlags = NodeFlagsContainsThis // Indicates whether the identifier contains an extended unicode escape sequence
+ NodeFlagsIdentifierIsInJSDocNamespace NodeFlags = NodeFlagsHasAsyncFunctions // Indicates whether the identifier is part of a JSDoc namespace
+)
+
+type ModifierFlags uint32
+
+const (
+ ModifierFlagsNone ModifierFlags = 0
+ // Syntactic/JSDoc modifiers
+ ModifierFlagsPublic ModifierFlags = 1 << 0 // Property/Method
+ ModifierFlagsPrivate ModifierFlags = 1 << 1 // Property/Method
+ ModifierFlagsProtected ModifierFlags = 1 << 2 // Property/Method
+ ModifierFlagsReadonly ModifierFlags = 1 << 3 // Property/Method
+ ModifierFlagsOverride ModifierFlags = 1 << 4 // Override method
+ // Syntactic-only modifiers
+ ModifierFlagsExport ModifierFlags = 1 << 5 // Declarations
+ ModifierFlagsAbstract ModifierFlags = 1 << 6 // Class/Method/ConstructSignature
+ ModifierFlagsAmbient ModifierFlags = 1 << 7 // Declarations
+ ModifierFlagsStatic ModifierFlags = 1 << 8 // Property/Method
+ ModifierFlagsAccessor ModifierFlags = 1 << 9 // Property
+ ModifierFlagsAsync ModifierFlags = 1 << 10 // Property/Method/Function
+ ModifierFlagsDefault ModifierFlags = 1 << 11 // Function/Class (export default declaration)
+ ModifierFlagsConst ModifierFlags = 1 << 12 // Const enum
+ ModifierFlagsIn ModifierFlags = 1 << 13 // Contravariance modifier
+ ModifierFlagsOut ModifierFlags = 1 << 14 // Covariance modifier
+ ModifierFlagsDecorator ModifierFlags = 1 << 15 // Contains a decorator.
+ ModifierFlagsImmediate ModifierFlags = 1 << 16 // Parameter
+ // JSDoc-only modifiers
+ ModifierFlagsDeprecated ModifierFlags = 1 << 17 // Deprecated tag.
+ ModifierFlagsJSDocImmediate ModifierFlags = 1 << 18 // Parameter
+ // Cache-only JSDoc-modifiers. Should match order of Syntactic/JSDoc modifiers, above.
+ ModifierFlagsJSDocPublic ModifierFlags = 1 << 23 // if this value changes, `selectEffectiveModifierFlags` must change accordingly
+ ModifierFlagsJSDocPrivate ModifierFlags = 1 << 24
+ ModifierFlagsJSDocProtected ModifierFlags = 1 << 25
+ ModifierFlagsJSDocReadonly ModifierFlags = 1 << 26
+ ModifierFlagsJSDocOverride ModifierFlags = 1 << 27
+ ModifierFlagsHasComputedJSDocModifiers ModifierFlags = 1 << 28 // Indicates the computed modifier flags include modifiers from JSDoc.
+ ModifierFlagsHasComputedFlags ModifierFlags = 1 << 29 // Modifier flags have been computed
+
+ ModifierFlagsSyntacticOrJSDocModifiers = ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected | ModifierFlagsReadonly | ModifierFlagsOverride
+ ModifierFlagsSyntacticOnlyModifiers = ModifierFlagsExport | ModifierFlagsAmbient | ModifierFlagsAbstract | ModifierFlagsStatic | ModifierFlagsAccessor | ModifierFlagsAsync | ModifierFlagsDefault | ModifierFlagsConst | ModifierFlagsIn | ModifierFlagsOut | ModifierFlagsDecorator | ModifierFlagsImmediate
+ ModifierFlagsSyntacticModifiers = ModifierFlagsSyntacticOrJSDocModifiers | ModifierFlagsSyntacticOnlyModifiers
+ ModifierFlagsJSDocCacheOnlyModifiers = ModifierFlagsJSDocPublic | ModifierFlagsJSDocPrivate | ModifierFlagsJSDocProtected | ModifierFlagsJSDocReadonly | ModifierFlagsJSDocOverride
+ ModifierFlagsJSDocOnlyModifiers = ModifierFlagsDeprecated | ModifierFlagsJSDocImmediate
+ ModifierFlagsNonCacheOnlyModifiers = ModifierFlagsSyntacticOrJSDocModifiers | ModifierFlagsSyntacticOnlyModifiers | ModifierFlagsJSDocOnlyModifiers
+
+ ModifierFlagsAccessibilityModifier = ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected
+ // Accessibility modifiers and 'readonly' can be attached to a parameter in a constructor to make it a property.
+ ModifierFlagsParameterPropertyModifier = ModifierFlagsAccessibilityModifier | ModifierFlagsReadonly | ModifierFlagsOverride
+ ModifierFlagsNonPublicAccessibilityModifier = ModifierFlagsPrivate | ModifierFlagsProtected
+
+ ModifierFlagsTypeScriptModifier = ModifierFlagsAmbient | ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected | ModifierFlagsReadonly | ModifierFlagsAbstract | ModifierFlagsConst | ModifierFlagsOverride | ModifierFlagsIn | ModifierFlagsOut | ModifierFlagsImmediate
+ ModifierFlagsExportDefault = ModifierFlagsExport | ModifierFlagsDefault
+ ModifierFlagsAll = ModifierFlagsExport | ModifierFlagsAmbient | ModifierFlagsPublic | ModifierFlagsPrivate | ModifierFlagsProtected | ModifierFlagsStatic | ModifierFlagsReadonly | ModifierFlagsAbstract | ModifierFlagsAccessor | ModifierFlagsAsync | ModifierFlagsDefault | ModifierFlagsConst | ModifierFlagsDeprecated | ModifierFlagsOverride | ModifierFlagsIn | ModifierFlagsOut | ModifierFlagsImmediate | ModifierFlagsDecorator
+ ModifierFlagsModifier = ModifierFlagsAll & ^ModifierFlagsDecorator
+)
+
+// SignatureFlags
+
+type SignatureFlags uint32
+
+const (
+ SignatureFlagsNone SignatureFlags = 0
+ SignatureFlagsYield SignatureFlags = 1 << 0
+ SignatureFlagsAwait SignatureFlags = 1 << 1
+ SignatureFlagsType SignatureFlags = 1 << 2
+ SignatureFlagsIgnoreMissingOpenBrace SignatureFlags = 1 << 4
+ SignatureFlagsJSDoc SignatureFlags = 1 << 5
+)
+
+// SymbolFlags
+
+type SymbolFlags uint32
+
+const (
+ SymbolFlagsNone SymbolFlags = 0
+ SymbolFlagsFunctionScopedVariable SymbolFlags = 1 << 0 // Variable (var) or parameter
+ SymbolFlagsBlockScopedVariable SymbolFlags = 1 << 1 // A block-scoped variable (let or const)
+ SymbolFlagsProperty SymbolFlags = 1 << 2 // Property or enum member
+ SymbolFlagsEnumMember SymbolFlags = 1 << 3 // Enum member
+ SymbolFlagsFunction SymbolFlags = 1 << 4 // Function
+ SymbolFlagsClass SymbolFlags = 1 << 5 // Class
+ SymbolFlagsInterface SymbolFlags = 1 << 6 // Interface
+ SymbolFlagsConstEnum SymbolFlags = 1 << 7 // Const enum
+ SymbolFlagsRegularEnum SymbolFlags = 1 << 8 // Enum
+ SymbolFlagsValueModule SymbolFlags = 1 << 9 // Instantiated module
+ SymbolFlagsNamespaceModule SymbolFlags = 1 << 10 // Uninstantiated module
+ SymbolFlagsTypeLiteral SymbolFlags = 1 << 11 // Type Literal or mapped type
+ SymbolFlagsObjectLiteral SymbolFlags = 1 << 12 // Object Literal
+ SymbolFlagsMethod SymbolFlags = 1 << 13 // Method
+ SymbolFlagsConstructor SymbolFlags = 1 << 14 // Constructor
+ SymbolFlagsGetAccessor SymbolFlags = 1 << 15 // Get accessor
+ SymbolFlagsSetAccessor SymbolFlags = 1 << 16 // Set accessor
+ SymbolFlagsSignature SymbolFlags = 1 << 17 // Call, construct, or index signature
+ SymbolFlagsTypeParameter SymbolFlags = 1 << 18 // Type parameter
+ SymbolFlagsTypeAlias SymbolFlags = 1 << 19 // Type alias
+ SymbolFlagsExportValue SymbolFlags = 1 << 20 // Exported value marker (see comment in declareModuleMember in binder)
+ SymbolFlagsAlias SymbolFlags = 1 << 21 // An alias for another symbol (see comment in isAliasSymbolDeclaration in checker)
+ SymbolFlagsPrototype SymbolFlags = 1 << 22 // Prototype property (no source representation)
+ SymbolFlagsExportStar SymbolFlags = 1 << 23 // Export * declaration
+ SymbolFlagsOptional SymbolFlags = 1 << 24 // Optional property
+ SymbolFlagsTransient SymbolFlags = 1 << 25 // Transient symbol (created during type check)
+ SymbolFlagsAssignment SymbolFlags = 1 << 26 // Assignment treated as declaration (eg `this.prop = 1`)
+ SymbolFlagsModuleExports SymbolFlags = 1 << 27 // Symbol for CommonJS `module` of `module.exports`
+ SymbolFlagsAll SymbolFlags = 0xFFFFFFFF
+
+ SymbolFlagsEnum = SymbolFlagsRegularEnum | SymbolFlagsConstEnum
+ SymbolFlagsVariable = SymbolFlagsFunctionScopedVariable | SymbolFlagsBlockScopedVariable
+ SymbolFlagsValue = SymbolFlagsVariable | SymbolFlagsProperty | SymbolFlagsEnumMember | SymbolFlagsObjectLiteral | SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsEnum | SymbolFlagsValueModule | SymbolFlagsMethod | SymbolFlagsGetAccessor | SymbolFlagsSetAccessor
+ SymbolFlagsType = SymbolFlagsClass | SymbolFlagsInterface | SymbolFlagsEnum | SymbolFlagsEnumMember | SymbolFlagsTypeLiteral | SymbolFlagsTypeParameter | SymbolFlagsTypeAlias
+ SymbolFlagsNamespace = SymbolFlagsValueModule | SymbolFlagsNamespaceModule | SymbolFlagsEnum
+ SymbolFlagsModule = SymbolFlagsValueModule | SymbolFlagsNamespaceModule
+ SymbolFlagsAccessor = SymbolFlagsGetAccessor | SymbolFlagsSetAccessor
+
+ // Variables can be redeclared, but can not redeclare a block-scoped declaration with the
+ // same name, or any other value that is not a variable, e.g. ValueModule or Class
+ SymbolFlagsFunctionScopedVariableExcludes = SymbolFlagsValue & ^SymbolFlagsFunctionScopedVariable
+
+ // Block-scoped declarations are not allowed to be re-declared
+ // they can not merge with anything in the value space
+ SymbolFlagsBlockScopedVariableExcludes = SymbolFlagsValue
+
+ SymbolFlagsParameterExcludes = SymbolFlagsValue
+ SymbolFlagsPropertyExcludes = SymbolFlagsNone
+ SymbolFlagsEnumMemberExcludes = SymbolFlagsValue | SymbolFlagsType
+ SymbolFlagsFunctionExcludes = SymbolFlagsValue & ^(SymbolFlagsFunction | SymbolFlagsValueModule | SymbolFlagsClass)
+ SymbolFlagsClassExcludes = (SymbolFlagsValue | SymbolFlagsType) & ^(SymbolFlagsValueModule | SymbolFlagsInterface | SymbolFlagsFunction) // class-interface mergability done in checker.ts
+ SymbolFlagsInterfaceExcludes = SymbolFlagsType & ^(SymbolFlagsInterface | SymbolFlagsClass)
+ SymbolFlagsRegularEnumExcludes = (SymbolFlagsValue | SymbolFlagsType) & ^(SymbolFlagsRegularEnum | SymbolFlagsValueModule) // regular enums merge only with regular enums and modules
+ SymbolFlagsConstEnumExcludes = (SymbolFlagsValue | SymbolFlagsType) & ^SymbolFlagsConstEnum // const enums merge only with const enums
+ SymbolFlagsValueModuleExcludes = SymbolFlagsValue & ^(SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsRegularEnum | SymbolFlagsValueModule)
+ SymbolFlagsNamespaceModuleExcludes = SymbolFlagsNone
+ SymbolFlagsMethodExcludes = SymbolFlagsValue & ^SymbolFlagsMethod
+ SymbolFlagsGetAccessorExcludes = SymbolFlagsValue & ^SymbolFlagsSetAccessor
+ SymbolFlagsSetAccessorExcludes = SymbolFlagsValue & ^SymbolFlagsGetAccessor
+ SymbolFlagsAccessorExcludes = SymbolFlagsValue & ^SymbolFlagsAccessor
+ SymbolFlagsTypeParameterExcludes = SymbolFlagsType & ^SymbolFlagsTypeParameter
+ SymbolFlagsTypeAliasExcludes = SymbolFlagsType
+ SymbolFlagsAliasExcludes = SymbolFlagsAlias
+ SymbolFlagsModuleMember = SymbolFlagsVariable | SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsInterface | SymbolFlagsEnum | SymbolFlagsModule | SymbolFlagsTypeAlias | SymbolFlagsAlias
+ SymbolFlagsExportHasLocal = SymbolFlagsFunction | SymbolFlagsClass | SymbolFlagsEnum | SymbolFlagsValueModule
+ SymbolFlagsBlockScoped = SymbolFlagsBlockScopedVariable | SymbolFlagsClass | SymbolFlagsEnum
+ SymbolFlagsPropertyOrAccessor = SymbolFlagsProperty | SymbolFlagsAccessor
+ SymbolFlagsClassMember = SymbolFlagsMethod | SymbolFlagsAccessor | SymbolFlagsProperty
+ SymbolFlagsExportSupportsDefaultModifier = SymbolFlagsClass | SymbolFlagsFunction | SymbolFlagsInterface
+ SymbolFlagsExportDoesNotSupportDefaultModifier = ^SymbolFlagsExportSupportsDefaultModifier
+ // The set of things we consider semantically classifiable. Used to speed up the LS during
+ // classification.
+ SymbolFlagsClassifiable = SymbolFlagsClass | SymbolFlagsEnum | SymbolFlagsTypeAlias | SymbolFlagsInterface | SymbolFlagsTypeParameter | SymbolFlagsModule | SymbolFlagsAlias
+ SymbolFlagsLateBindingContainer = SymbolFlagsClass | SymbolFlagsInterface | SymbolFlagsTypeLiteral | SymbolFlagsObjectLiteral | SymbolFlagsFunction
+)
+
+// CheckFlags
+
+type CheckFlags = uint32
+
+const (
+ CheckFlagsNone CheckFlags = 0
+ CheckFlagsInstantiated CheckFlags = 1 << 0 // Instantiated symbol
+ CheckFlagsSyntheticProperty CheckFlags = 1 << 1 // Property in union or intersection type
+ CheckFlagsSyntheticMethod CheckFlags = 1 << 2 // Method in union or intersection type
+ CheckFlagsReadonly CheckFlags = 1 << 3 // Readonly transient symbol
+ CheckFlagsReadPartial CheckFlags = 1 << 4 // Synthetic property present in some but not all constituents
+ CheckFlagsWritePartial CheckFlags = 1 << 5 // Synthetic property present in some but only satisfied by an index signature in others
+ CheckFlagsHasNonUniformType CheckFlags = 1 << 6 // Synthetic property with non-uniform type in constituents
+ CheckFlagsHasLiteralType CheckFlags = 1 << 7 // Synthetic property with at least one literal type in constituents
+ CheckFlagsContainsPublic CheckFlags = 1 << 8 // Synthetic property with public constituent(s)
+ CheckFlagsContainsProtected CheckFlags = 1 << 9 // Synthetic property with protected constituent(s)
+ CheckFlagsContainsPrivate CheckFlags = 1 << 10 // Synthetic property with private constituent(s)
+ CheckFlagsContainsStatic CheckFlags = 1 << 11 // Synthetic property with static constituent(s)
+ CheckFlagsLate CheckFlags = 1 << 12 // Late-bound symbol for a computed property with a dynamic name
+ CheckFlagsReverseMapped CheckFlags = 1 << 13 // Property of reverse-inferred homomorphic mapped type
+ CheckFlagsOptionalParameter CheckFlags = 1 << 14 // Optional parameter
+ CheckFlagsRestParameter CheckFlags = 1 << 15 // Rest parameter
+ CheckFlagsDeferredType CheckFlags = 1 << 16 // Calculation of the type of this symbol is deferred due to processing costs, should be fetched with `getTypeOfSymbolWithDeferredType`
+ CheckFlagsHasNeverType CheckFlags = 1 << 17 // Synthetic property with at least one never type in constituents
+ CheckFlagsMapped CheckFlags = 1 << 18 // Property of mapped type
+ CheckFlagsStripOptional CheckFlags = 1 << 19 // Strip optionality in mapped property
+ CheckFlagsUnresolved CheckFlags = 1 << 20 // Unresolved type alias symbol
+ CheckFlagsSynthetic = CheckFlagsSyntheticProperty | CheckFlagsSyntheticMethod
+ CheckFlagsDiscriminant = CheckFlagsHasNonUniformType | CheckFlagsHasLiteralType
+ CheckFlagsPartial = CheckFlagsReadPartial | CheckFlagsWritePartial
+)
+
+type SignatureKind int32
+
+const (
+ SignatureKindCall SignatureKind = iota
+ SignatureKindConstruct
+)
+
+type ScriptKind int32
+
+const (
+ ScriptKindUnknown ScriptKind = iota
+ ScriptKindJS
+ ScriptKindJSX
+ ScriptKindTS
+ ScriptKindTSX
+ ScriptKindExternal
+ ScriptKindJSON
+ /**
+ * Used on extensions that doesn't define the ScriptKind but the content defines it.
+ * Deferred extensions are going to be included in all project contexts.
+ */
+ ScriptKindDeferred
+)
+
+type ScriptTarget int32
+
+const (
+ ScriptTargetNone ScriptTarget = 0
+ ScriptTargetES3 ScriptTarget = 0 // Deprecated
+ ScriptTargetES5 ScriptTarget = 1
+ ScriptTargetES2015 ScriptTarget = 2
+ ScriptTargetES2016 ScriptTarget = 3
+ ScriptTargetES2017 ScriptTarget = 4
+ ScriptTargetES2018 ScriptTarget = 5
+ ScriptTargetES2019 ScriptTarget = 6
+ ScriptTargetES2020 ScriptTarget = 7
+ ScriptTargetES2021 ScriptTarget = 8
+ ScriptTargetES2022 ScriptTarget = 9
+ ScriptTargetES2023 ScriptTarget = 10
+ ScriptTargetESNext ScriptTarget = 99
+ ScriptTargetJSON ScriptTarget = 100
+ ScriptTargetLatest ScriptTarget = ScriptTargetESNext
+)
+
+type LanguageVariant int32
+
+const (
+ LanguageVariantStandard LanguageVariant = iota
+ LanguageVariantJSX
+)
+
+// Ids
+
+type NodeId uint32
+type SymbolId uint32
+type MergeId uint32
+type TypeId uint32
+
+// Symbol
+
+type Symbol struct {
+ flags SymbolFlags
+ checkFlags CheckFlags // Non-zero only in transient symbols
+ constEnumOnlyModule bool // True if module contains only const enums or other modules with only const enums
+ isReplaceableByMethod bool
+ name string
+ declarations []*Node
+ valueDeclaration *Node
+ members SymbolTable
+ exports SymbolTable
+ id SymbolId
+ mergeId MergeId // Assigned once symbol is merged somewhere
+ parent *Symbol
+ exportSymbol *Symbol
+ assignmentDeclarationMembers map[NodeId]*Node // Set of detected assignment declarations
+ globalExports SymbolTable // Conditional global UMD exports
+}
+
+// SymbolTable
+
+type SymbolTable map[string]*Symbol
+
+// Links for value symbols
+
+type ValueSymbolLinks struct {
+ resolvedType *Type // Type of value symbol
+}
+
+// Links for alias symbols
+
+type AliasSymbolLinks struct {
+ immediateTarget *Symbol // Immediate target of an alias. May be another alias. Do not access directly, use `checker.getImmediateAliasedSymbol` instead.
+ aliasTarget *Symbol // Resolved (non-alias) target of an alias
+ typeOnlyDeclarationResolved bool // True when typeOnlyDeclaration resolution in process
+ typeOnlyDeclaration *Node // First resolved alias declaration that makes the symbol only usable in type constructs
+ typeOnlyExportStarName string // Set to the name of the symbol re-exported by an 'export type *' declaration, when different from the symbol name
+}
+
+// Links for module symbols
+
+type ModuleSymbolLinks struct {
+ resolvedExports SymbolTable // Resolved exports of module or combined early- and late-bound static members of a class.
+ cjsExportMerged *Symbol // Version of the symbol with all non export= exports merged with the export= target
+ typeOnlyExportStarMap map[string]*Node // Set on a module symbol when some of its exports were resolved through a 'export type * from "mod"' declaration
+}
+
+// Links for export type symbols
+
+type ExportTypeLinks struct {
+ target *Symbol // Target symbol
+ originatingImport *Node // Import declaration which produced the symbol, present if the symbol is marked as uncallable but had call signatures in `resolveESModuleSymbol`
+}
+
+// Links for late-binding containers
+
+type MembersOrExportsResolutionKind int
+
+const (
+ MembersOrExportsResolutionKindResolvedExports MembersOrExportsResolutionKind = 0
+ MembersOrExportsResolutionKindresolvedMembers MembersOrExportsResolutionKind = 1
+)
+
+type MembersAndExportsLinks [2]SymbolTable // Indexed by MembersOrExportsResolutionKind
+
+// Links for type parameters
+
+type TypeParameterLinks struct {
+ declaredType *Type
+}
+
+// Links for interface types
+
+type InterfaceTypeLinks struct {
+ declaredType *Type
+}
+
+// FlowFlags
+
+type FlowFlags uint32
+
+const (
+ FlowFlagsUnreachable FlowFlags = 1 << 0 // Unreachable code
+ FlowFlagsStart FlowFlags = 1 << 1 // Start of flow graph
+ FlowFlagsBranchLabel FlowFlags = 1 << 2 // Non-looping junction
+ FlowFlagsLoopLabel FlowFlags = 1 << 3 // Looping junction
+ FlowFlagsAssignment FlowFlags = 1 << 4 // Assignment
+ FlowFlagsTrueCondition FlowFlags = 1 << 5 // Condition known to be true
+ FlowFlagsFalseCondition FlowFlags = 1 << 6 // Condition known to be false
+ FlowFlagsSwitchClause FlowFlags = 1 << 7 // Switch statement clause
+ FlowFlagsArrayMutation FlowFlags = 1 << 8 // Potential array mutation
+ FlowFlagsCall FlowFlags = 1 << 9 // Potential assertion call
+ FlowFlagsReduceLabel FlowFlags = 1 << 10 // Temporarily reduce antecedents of label
+ FlowFlagsReferenced FlowFlags = 1 << 11 // Referenced as antecedent once
+ FlowFlagsShared FlowFlags = 1 << 12 // Referenced as antecedent more than once
+ FlowFlagsLabel = FlowFlagsBranchLabel | FlowFlagsLoopLabel
+ FlowFlagsCondition = FlowFlagsTrueCondition | FlowFlagsFalseCondition
+)
+
+// FlowNode
+
+type FlowNode struct {
+ flags FlowFlags
+ node any
+ antecedent *FlowNode // Antecedent for all but FlowLabel
+ antecedents *FlowList // Linked list of antecedents for FlowLabel
+}
+
+type FlowList struct {
+ node *FlowNode
+ next *FlowList
+}
+
+type FlowLabel = FlowNode
+
+var unreachableFlow = &FlowNode{flags: FlowFlagsUnreachable}
+var reportedUnreachableFlow = &FlowNode{flags: FlowFlagsUnreachable}
+
+// FlowSwitchClauseData
+
+type FlowSwitchClauseData struct {
+ switchStatement *SwitchStatement
+ clauseStart int32 // Start index of case/default clause range
+ clauseEnd int32 // End index of case/default clause range
+}
+
+// FlowReduceLabelData
+
+type FlowReduceLabelData struct {
+ target *FlowLabel // Target label
+ antecedents *FlowList // Temporary antecedent list
+}
+
+// Tristate
+
+type Tristate byte
+
+const (
+ TSUnknown Tristate = iota
+ TSFalse
+ TSTrue
+)
+
+type VarianceFlags uint32
+
+const (
+ VarianceFlagsInvariant VarianceFlags = 0 // Neither covariant nor contravariant
+ VarianceFlagsCovariant VarianceFlags = 1 << 0 // Covariant
+ VarianceFlagsContravariant VarianceFlags = 1 << 1 // Contravariant
+ VarianceFlagsBivariant VarianceFlags = VarianceFlagsCovariant | VarianceFlagsContravariant // Both covariant and contravariant
+ VarianceFlagsIndependent VarianceFlags = 1 << 2 // Unwitnessed type parameter
+ VarianceFlagsVarianceMask VarianceFlags = VarianceFlagsInvariant | VarianceFlagsCovariant | VarianceFlagsContravariant | VarianceFlagsIndependent // Mask containing all measured variances without the unmeasurable flag
+ VarianceFlagsUnmeasurable VarianceFlags = 1 << 3 // Variance result is unusable - relationship relies on structural comparisons which are not reflected in generic relationships
+ VarianceFlagsUnreliable VarianceFlags = 1 << 4 // Variance result is unreliable - checking may produce false negatives, but not false positives
+ VarianceFlagsAllowsStructuralFallback = VarianceFlagsUnmeasurable | VarianceFlagsUnreliable
+)
+
+type AccessFlags uint32
+
+type AssignmentDeclarationKind = int32
+
+const (
+ AssignmentDeclarationKindNone = AssignmentDeclarationKind(iota)
+ /// exports.name = expr
+ /// module.exports.name = expr
+ AssignmentDeclarationKindExportsProperty
+ /// module.exports = expr
+ AssignmentDeclarationKindModuleExports
+ /// className.prototype.name = expr
+ AssignmentDeclarationKindPrototypeProperty
+ /// this.name = expr
+ AssignmentDeclarationKindThisProperty
+ // F.name = expr
+ AssignmentDeclarationKindProperty
+ // F.prototype = { ... }
+ AssignmentDeclarationKindPrototype
+ // Object.defineProperty(x, 'name', { value: any, writable?: boolean (false by default) });
+ // Object.defineProperty(x, 'name', { get: Function, set: Function });
+ // Object.defineProperty(x, 'name', { get: Function });
+ // Object.defineProperty(x, 'name', { set: Function });
+ AssignmentDeclarationKindObjectDefinePropertyValue
+ // Object.defineProperty(exports || module.exports, 'name', ...);
+ AssignmentDeclarationKindObjectDefinePropertyExports
+ // Object.defineProperty(Foo.prototype, 'name', ...);
+ AssignmentDeclarationKindObjectDefinePrototypeProperty
+)
+
+const InternalSymbolNamePrefix = "\xFE" // Invalid UTF8 sequence, will never occur as IdentifierName
+
+const (
+ InternalSymbolNameCall = InternalSymbolNamePrefix + "call" // Call signatures
+ InternalSymbolNameConstructor = InternalSymbolNamePrefix + "constructor" // Constructor implementations
+ InternalSymbolNameNew = InternalSymbolNamePrefix + "new" // Constructor signatures
+ InternalSymbolNameIndex = InternalSymbolNamePrefix + "index" // Index signatures
+ InternalSymbolNameExportStar = InternalSymbolNamePrefix + "export" // Module export * declarations
+ InternalSymbolNameGlobal = InternalSymbolNamePrefix + "global" // Global self-reference
+ InternalSymbolNameMissing = InternalSymbolNamePrefix + "missing" // Indicates missing symbol
+ InternalSymbolNameType = InternalSymbolNamePrefix + "type" // Anonymous type literal symbol
+ InternalSymbolNameObject = InternalSymbolNamePrefix + "object" // Anonymous object literal declaration
+ InternalSymbolNameJSXAttributes = InternalSymbolNamePrefix + "jsxAttributes" // Anonymous JSX attributes object literal declaration
+ InternalSymbolNameClass = InternalSymbolNamePrefix + "class" // Unnamed class expression
+ InternalSymbolNameFunction = InternalSymbolNamePrefix + "function" // Unnamed function expression
+ InternalSymbolNameComputed = InternalSymbolNamePrefix + "computed" // Computed property name declaration with dynamic name
+ InternalSymbolNameResolving = InternalSymbolNamePrefix + "resolving" // Indicator symbol used to mark partially resolved type aliases
+ InternalSymbolNameExportEquals = InternalSymbolNamePrefix + "export=" // Export assignment symbol
+ InternalSymbolNameInstantiationExpression = InternalSymbolNamePrefix + "instantiationExpression" // Instantiation expressions
+ InternalSymbolNameImportAttributes = InternalSymbolNamePrefix + "importAttributes"
+ InternalSymbolNameDefault = "default" // Default export symbol (technically not wholly internal, but included here for usability)
+ InternalSymbolNameThis = "this"
+)
+
+// CompilerOptions
+
+type CompilerOptions struct {
+ AllowSyntheticDefaultImports Tristate
+ AllowUmdGlobalAccess Tristate
+ AllowUnreachableCode Tristate
+ AllowUnusedLabels Tristate
+ CheckJs Tristate
+ ESModuleInterop Tristate
+ ExactOptionalPropertyTypes Tristate
+ IsolatedModules Tristate
+ ModuleKind ModuleKind
+ ModuleResolution ModuleResolutionKind
+ NoFallthroughCasesInSwitch Tristate
+ NoImplicitAny Tristate
+ PreserveConstEnums Tristate
+ Strict Tristate
+ StrictNullChecks Tristate
+ Target ScriptTarget
+ Types []string
+ UseDefineForClassFields Tristate
+ UseUnknownInCatchVariables Tristate
+ VerbatimModuleSyntax Tristate
+}
+
+type ModuleKind int32
+
+const (
+ ModuleKindNone ModuleKind = 0
+ ModuleKindCommonJS ModuleKind = 1
+ ModuleKindAMD ModuleKind = 2
+ ModuleKindUMD ModuleKind = 3
+ ModuleKindSystem ModuleKind = 4
+ // NOTE: ES module kinds should be contiguous to more easily check whether a module kind is *any* ES module kind.
+ // Non-ES module kinds should not come between ES2015 (the earliest ES module kind) and ESNext (the last ES
+ // module kind).
+ ModuleKindES2015 ModuleKind = 5
+ ModuleKindES2020 ModuleKind = 6
+ ModuleKindES2022 ModuleKind = 7
+ ModuleKindESNext ModuleKind = 99
+ // Node16+ is an amalgam of commonjs (albeit updated) and es2022+, and represents a distinct module system from es2020/esnext
+ ModuleKindNode16 ModuleKind = 100
+ ModuleKindNodeNext ModuleKind = 199
+ // Emit as written
+ ModuleKindPreserve ModuleKind = 200
+)
+
+type ResolutionMode = ModuleKind // ModuleKindNone | ModuleKindCommonJS | ModuleKindESNext
+
+type ModuleResolutionKind int32
+
+const (
+ ModuleResolutionKindUnknown ModuleResolutionKind = 0
+ ModuleResolutionKindClassic ModuleResolutionKind = 1
+ ModuleResolutionKindNode10 ModuleResolutionKind = 2
+ // Starting with node12, node's module resolver has significant departures from traditional cjs resolution
+ // to better support ECMAScript modules and their use within node - however more features are still being added.
+ // TypeScript's Node ESM support was introduced after Node 12 went end-of-life, and Node 14 is the earliest stable
+ // version that supports both pattern trailers - *but*, Node 16 is the first version that also supports ECMAScript 2022.
+ // In turn, we offer both a `NodeNext` moving resolution target, and a `Node16` version-anchored resolution target
+ ModuleResolutionKindNode16 ModuleResolutionKind = 3
+ ModuleResolutionKindNodeNext ModuleResolutionKind = 99 // Not simply `Node16` so that compiled code linked against TS can use the `Next` value reliably (same as with `ModuleKind`)
+ ModuleResolutionKindBundler ModuleResolutionKind = 100
+)
+
+type NodeCheckFlags uint32
+
+const (
+ NodeCheckFlagsNone NodeCheckFlags = 0
+ NodeCheckFlagsTypeChecked NodeCheckFlags = 1 << 0 // Node has been type checked
+ NodeCheckFlagsLexicalThis NodeCheckFlags = 1 << 1 // Lexical 'this' reference
+ NodeCheckFlagsCaptureThis NodeCheckFlags = 1 << 2 // Lexical 'this' used in body
+ NodeCheckFlagsCaptureNewTarget NodeCheckFlags = 1 << 3 // Lexical 'new.target' used in body
+ NodeCheckFlagsSuperInstance NodeCheckFlags = 1 << 4 // Instance 'super' reference
+ NodeCheckFlagsSuperStatic NodeCheckFlags = 1 << 5 // Static 'super' reference
+ NodeCheckFlagsContextChecked NodeCheckFlags = 1 << 6 // Contextual types have been assigned
+ NodeCheckFlagsMethodWithSuperPropertyAccessInAsync NodeCheckFlags = 1 << 7 // A method that contains a SuperProperty access in an async context.
+ NodeCheckFlagsMethodWithSuperPropertyAssignmentInAsync NodeCheckFlags = 1 << 8 // A method that contains a SuperProperty assignment in an async context.
+ NodeCheckFlagsCaptureArguments NodeCheckFlags = 1 << 9 // Lexical 'arguments' used in body
+ NodeCheckFlagsEnumValuesComputed NodeCheckFlags = 1 << 10 // Values for enum members have been computed, and any errors have been reported for them.
+ NodeCheckFlagsLexicalModuleMergesWithClass NodeCheckFlags = 1 << 11 // Instantiated lexical module declaration is merged with a previous class declaration.
+ NodeCheckFlagsLoopWithCapturedBlockScopedBinding NodeCheckFlags = 1 << 12 // Loop that contains block scoped variable captured in closure
+ NodeCheckFlagsContainsCapturedBlockScopeBinding NodeCheckFlags = 1 << 13 // Part of a loop that contains block scoped variable captured in closure
+ NodeCheckFlagsCapturedBlockScopedBinding NodeCheckFlags = 1 << 14 // Block-scoped binding that is captured in some function
+ NodeCheckFlagsBlockScopedBindingInLoop NodeCheckFlags = 1 << 15 // Block-scoped binding with declaration nested inside iteration statement
+ NodeCheckFlagsNeedsLoopOutParameter NodeCheckFlags = 1 << 16 // Block scoped binding whose value should be explicitly copied outside of the converted loop
+ NodeCheckFlagsAssignmentsMarked NodeCheckFlags = 1 << 17 // Parameter assignments have been marked
+ NodeCheckFlagsContainsConstructorReference NodeCheckFlags = 1 << 18 // Class or class element that contains a binding that references the class constructor.
+ NodeCheckFlagsConstructorReference NodeCheckFlags = 1 << 29 // Binding to a class constructor inside of the class's body.
+ NodeCheckFlagsContainsClassWithPrivateIdentifiers NodeCheckFlags = 1 << 20 // Marked on all block-scoped containers containing a class with private identifiers.
+ NodeCheckFlagsContainsSuperPropertyInStaticInitializer NodeCheckFlags = 1 << 21 // Marked on all block-scoped containers containing a static initializer with 'super.x' or 'super[x]'.
+ NodeCheckFlagsInCheckIdentifier NodeCheckFlags = 1 << 22
+ NodeCheckFlagsPartiallyTypeChecked NodeCheckFlags = 1 << 23 // Node has been partially type checked
+)
+
+// Common links
+
+type NodeLinks struct {
+ flags NodeCheckFlags // Set of flags specific to Node
+ declarationRequiresScopeChange Tristate
+ resolvedType *Type // Cached type of type node
+ resolvedSymbol *Symbol // Cached name resolution result
+}
+
+// Signature specific links
+
+type SignatureLinks struct {
+ resolvedSignature *Signature
+ effectsSignature *Signature
+}
+
+// jsxFlag: JsxOpeningElement | JsxClosingElement
+// resolvedJsxElementAttributesType: JsxOpeningElement | JsxClosingElement
+// resolvedJsxElementAllAttributesType: JsxOpeningElement | JsxClosingElement
+// jsxNamespace: Jsx*
+// jsxImplicitImportContainer: Jsx*
+
+// resolvedJSDocType: JSDoc TypeReference | ImportType
+
+// switchTypes: SwitchStatement
+
+// contectFreeType: Expression | FunctionExpression | ArrowFunction | MethodDeclaration
+
+// outerTypeParameters: AnonymousType | MappedType | DeferredTypeReference
+
+// Only on SourceFile
+// deferredNodes []Node // Set of nodes whose checking has been deferred
+
+// resolvedSignature Signature; // Cached signature of signature node or call expression
+// effectsSignature Signature; // Signature with possible control flow effects
+// enumMemberValue EvaluatorResult; // Constant value of enum member
+// isVisible boolean; // Is this node visible
+// containsArgumentsReference boolean; // Whether a function-like declaration contains an 'arguments' reference
+// hasReportedStatementInAmbientContext boolean; // Cache boolean if we report statements in ambient context
+// jsxFlag JsxFlags; // flags for knowing what kind of element/attributes we're dealing with
+// resolvedJsxElementAttributesType Type; // resolved element attributes type of a JSX openinglike element
+// resolvedJsxElementAllAttributesType Type; // resolved all element attributes type of a JSX openinglike element
+// resolvedJSDocType Type; // Resolved type of a JSDoc type reference
+// switchTypes []Type; // Cached array of switch case expression types
+// jsxNamespace *Symbol; // Resolved jsx namespace symbol for this node
+// jsxImplicitImportContainer *Symbol; // Resolved module symbol the implicit jsx import of this file should refer to
+// contextFreeType Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive
+// deferredNodes []Node // Set of nodes whose checking has been deferred
+// capturedBlockScopeBindings []*Symbol; // Block-scoped bindings captured beneath this part of an IterationStatement
+// outerTypeParameters []*TypeParameter; // Outer type parameters of anonymous object type
+// isExhaustive boolean; // Is node an exhaustive switch statement (0 indicates in-process resolution)
+// skipDirectInference true; // Flag set by the API `getContextualType` call on a node when `Completions` is passed to force the checker to skip making inferences to a node's type
+// declarationRequiresScopeChange boolean; // Set by `useOuterVariableScopeInParameter` in checker when downlevel emit would change the name resolution scope inside of a parameter.
+// serializedTypes map[string]SerializedTypeEntry> // Collection of types serialized at this location
+// decoratorSignature Signature; // Signature for decorator as if invoked by the runtime.
+// spreadIndices { first: number | undefined, last: number | undefined }; // Indices of first and last spread elements in array literal
+// parameterInitializerContainsUndefined boolean; // True if this is a parameter declaration whose type annotation contains "undefined".
+// fakeScopeForSignatureDeclaration "params" | "typeParams"; // If present, this is a fake scope injected into an enclosing declaration chain.
+// assertionExpressionType Type; // Cached type of the expression of a type assertion
+// potentialThisCollisions Node[];
+// potentialNewTargetCollisions Node[];
+// potentialWeakMapSetCollisions Node[];
+// potentialReflectCollisions Node[];
+// potentialUnusedRenamedBindingElementsInTypes BindingElement[];
+// externalHelpersModule Symbol; // Resolved symbol for the external helpers module
+// instantiationExpressionTypes Map; // Cache of instantiation expression types for the node
+
+type TypeFlags uint32
+
+const (
+ TypeFlagsNone TypeFlags = 0
+ TypeFlagsAny TypeFlags = 1 << 0
+ TypeFlagsUnknown TypeFlags = 1 << 1
+ TypeFlagsString TypeFlags = 1 << 2
+ TypeFlagsNumber TypeFlags = 1 << 3
+ TypeFlagsBoolean TypeFlags = 1 << 4
+ TypeFlagsEnum TypeFlags = 1 << 5 // Numeric computed enum member value
+ TypeFlagsBigint TypeFlags = 1 << 6
+ TypeFlagsStringLiteral TypeFlags = 1 << 7
+ TypeFlagsNumberLiteral TypeFlags = 1 << 8
+ TypeFlagsBooleanLiteral TypeFlags = 1 << 9
+ TypeFlagsEnumLiteral TypeFlags = 1 << 10 // Always combined with StringLiteral, NumberLiteral, or Union
+ TypeFlagsBigintLiteral TypeFlags = 1 << 11
+ TypeFlagsESSymbol TypeFlags = 1 << 12 // Type of symbol primitive introduced in ES6
+ TypeFlagsUniqueESSymbol TypeFlags = 1 << 13 // unique symbol
+ TypeFlagsVoid TypeFlags = 1 << 14
+ TypeFlagsUndefined TypeFlags = 1 << 15
+ TypeFlagsNull TypeFlags = 1 << 16
+ TypeFlagsNever TypeFlags = 1 << 17 // Never type
+ TypeFlagsTypeParameter TypeFlags = 1 << 18 // Type parameter
+ TypeFlagsObject TypeFlags = 1 << 19 // Object type
+ TypeFlagsUnion TypeFlags = 1 << 20 // Union (T | U)
+ TypeFlagsIntersection TypeFlags = 1 << 21 // Intersection (T & U)
+ TypeFlagsIndex TypeFlags = 1 << 22 // keyof T
+ TypeFlagsIndexedAccess TypeFlags = 1 << 23 // T[K]
+ TypeFlagsConditional TypeFlags = 1 << 24 // T extends U ? X : Y
+ TypeFlagsSubstitution TypeFlags = 1 << 25 // Type parameter substitution
+ TypeFlagsNonPrimitive TypeFlags = 1 << 26 // intrinsic object type
+ TypeFlagsTemplateLiteral TypeFlags = 1 << 27 // Template literal type
+ TypeFlagsStringMapping TypeFlags = 1 << 28 // Uppercase/Lowercase type
+ TypeFlagsReserved1 TypeFlags = 1 << 29 // Used by union/intersection type construction
+ TypeFlagsReserved2 TypeFlags = 1 << 30 // Used by union/intersection type construction
+ TypeFlagsReserved3 TypeFlags = 1 << 31
+
+ TypeFlagsAnyOrUnknown = TypeFlagsAny | TypeFlagsUnknown
+ TypeFlagsNullable = TypeFlagsUndefined | TypeFlagsNull
+ TypeFlagsLiteral = TypeFlagsStringLiteral | TypeFlagsNumberLiteral | TypeFlagsBigintLiteral | TypeFlagsBooleanLiteral
+ TypeFlagsUnit = TypeFlagsEnum | TypeFlagsLiteral | TypeFlagsUniqueESSymbol | TypeFlagsNullable
+ TypeFlagsFreshable = TypeFlagsEnum | TypeFlagsLiteral
+ TypeFlagsStringOrNumberLiteral = TypeFlagsStringLiteral | TypeFlagsNumberLiteral
+ TypeFlagsStringOrNumberLiteralOrUnique = TypeFlagsStringLiteral | TypeFlagsNumberLiteral | TypeFlagsUniqueESSymbol
+ TypeFlagsDefinitelyFalsy = TypeFlagsStringLiteral | TypeFlagsNumberLiteral | TypeFlagsBigintLiteral | TypeFlagsBooleanLiteral | TypeFlagsVoid | TypeFlagsUndefined | TypeFlagsNull
+ TypeFlagsPossiblyFalsy = TypeFlagsDefinitelyFalsy | TypeFlagsString | TypeFlagsNumber | TypeFlagsBigint | TypeFlagsBoolean
+ TypeFlagsIntrinsic = TypeFlagsAny | TypeFlagsUnknown | TypeFlagsString | TypeFlagsNumber | TypeFlagsBigint | TypeFlagsESSymbol | TypeFlagsVoid | TypeFlagsUndefined | TypeFlagsNull | TypeFlagsNever | TypeFlagsNonPrimitive
+ TypeFlagsStringLike = TypeFlagsString | TypeFlagsStringLiteral | TypeFlagsTemplateLiteral | TypeFlagsStringMapping
+ TypeFlagsNumberLike = TypeFlagsNumber | TypeFlagsNumberLiteral | TypeFlagsEnum
+ TypeFlagsBigIntLike = TypeFlagsBigint | TypeFlagsBigintLiteral
+ TypeFlagsBooleanLike = TypeFlagsBoolean | TypeFlagsBooleanLiteral
+ TypeFlagsEnumLike = TypeFlagsEnum | TypeFlagsEnumLiteral
+ TypeFlagsESSymbolLike = TypeFlagsESSymbol | TypeFlagsUniqueESSymbol
+ TypeFlagsVoidLike = TypeFlagsVoid | TypeFlagsUndefined
+ TypeFlagsPrimitive = TypeFlagsStringLike | TypeFlagsNumberLike | TypeFlagsBigIntLike | TypeFlagsBooleanLike | TypeFlagsEnumLike | TypeFlagsESSymbolLike | TypeFlagsVoidLike | TypeFlagsNull
+ TypeFlagsDefinitelyNonNullable = TypeFlagsStringLike | TypeFlagsNumberLike | TypeFlagsBigIntLike | TypeFlagsBooleanLike | TypeFlagsEnumLike | TypeFlagsESSymbolLike | TypeFlagsObject | TypeFlagsNonPrimitive
+ TypeFlagsDisjointDomains = TypeFlagsNonPrimitive | TypeFlagsStringLike | TypeFlagsNumberLike | TypeFlagsBigIntLike | TypeFlagsBooleanLike | TypeFlagsESSymbolLike | TypeFlagsVoidLike | TypeFlagsNull
+ TypeFlagsUnionOrIntersection = TypeFlagsUnion | TypeFlagsIntersection
+ TypeFlagsStructuredType = TypeFlagsObject | TypeFlagsUnion | TypeFlagsIntersection
+ TypeFlagsTypeVariable = TypeFlagsTypeParameter | TypeFlagsIndexedAccess
+ TypeFlagsInstantiableNonPrimitive = TypeFlagsTypeVariable | TypeFlagsConditional | TypeFlagsSubstitution
+ TypeFlagsInstantiablePrimitive = TypeFlagsIndex | TypeFlagsTemplateLiteral | TypeFlagsStringMapping
+ TypeFlagsInstantiable = TypeFlagsInstantiableNonPrimitive | TypeFlagsInstantiablePrimitive
+ TypeFlagsStructuredOrInstantiable = TypeFlagsStructuredType | TypeFlagsInstantiable
+ TypeFlagsObjectFlagsType = TypeFlagsAny | TypeFlagsNullable | TypeFlagsNever | TypeFlagsObject | TypeFlagsUnion | TypeFlagsIntersection
+ TypeFlagsSimplifiable = TypeFlagsIndexedAccess | TypeFlagsConditional
+ TypeFlagsSingleton = TypeFlagsAny | TypeFlagsUnknown | TypeFlagsString | TypeFlagsNumber | TypeFlagsBoolean | TypeFlagsBigint | TypeFlagsESSymbol | TypeFlagsVoid | TypeFlagsUndefined | TypeFlagsNull | TypeFlagsNever | TypeFlagsNonPrimitive
+ // 'TypeFlagsNarrowable' types are types where narrowing actually narrows.
+ // This *should* be every type other than null, undefined, void, and never
+ TypeFlagsNarrowable = TypeFlagsAny | TypeFlagsUnknown | TypeFlagsStructuredOrInstantiable | TypeFlagsStringLike | TypeFlagsNumberLike | TypeFlagsBigIntLike | TypeFlagsBooleanLike | TypeFlagsESSymbol | TypeFlagsUniqueESSymbol | TypeFlagsNonPrimitive
+ // The following flags are aggregated during union and intersection type construction
+ TypeFlagsIncludesMask = TypeFlagsAny | TypeFlagsUnknown | TypeFlagsPrimitive | TypeFlagsNever | TypeFlagsObject | TypeFlagsUnion | TypeFlagsIntersection | TypeFlagsNonPrimitive | TypeFlagsTemplateLiteral | TypeFlagsStringMapping
+ // The following flags are used for different purposes during union and intersection type construction
+ TypeFlagsIncludesMissingType = TypeFlagsTypeParameter
+ TypeFlagsIncludesNonWideningType = TypeFlagsIndex
+ TypeFlagsIncludesWildcard = TypeFlagsIndexedAccess
+ TypeFlagsIncludesEmptyObject = TypeFlagsConditional
+ TypeFlagsIncludesInstantiable = TypeFlagsSubstitution
+ TypeFlagsIncludesConstrainedTypeVariable = TypeFlagsReserved1
+ TypeFlagsIncludesError = TypeFlagsReserved2
+ TypeFlagsNotPrimitiveUnion = TypeFlagsAny | TypeFlagsUnknown | TypeFlagsVoid | TypeFlagsNever | TypeFlagsObject | TypeFlagsIntersection | TypeFlagsIncludesInstantiable
+)
+
+type ObjectFlags uint32
+
+// Types included in TypeFlags.ObjectFlagsType have an objectFlags property. Some ObjectFlags
+// are specific to certain types and reuse the same bit position. Those ObjectFlags require a check
+// for a certain TypeFlags value to determine their meaning.
+// dprint-ignore
+const (
+ ObjectFlagsNone ObjectFlags = 0
+ ObjectFlagsClass ObjectFlags = 1 << 0 // Class
+ ObjectFlagsInterface ObjectFlags = 1 << 1 // Interface
+ ObjectFlagsReference ObjectFlags = 1 << 2 // Generic type reference
+ ObjectFlagsTuple ObjectFlags = 1 << 3 // Synthesized generic tuple type
+ ObjectFlagsAnonymous ObjectFlags = 1 << 4 // Anonymous
+ ObjectFlagsMapped ObjectFlags = 1 << 5 // Mapped
+ ObjectFlagsInstantiated ObjectFlags = 1 << 6 // Instantiated anonymous or mapped type
+ ObjectFlagsObjectLiteral ObjectFlags = 1 << 7 // Originates in an object literal
+ ObjectFlagsEvolvingArray ObjectFlags = 1 << 8 // Evolving array type
+ ObjectFlagsObjectLiteralPatternWithComputedProperties ObjectFlags = 1 << 9 // Object literal pattern with computed properties
+ ObjectFlagsReverseMapped ObjectFlags = 1 << 10 // Object contains a property from a reverse-mapped type
+ ObjectFlagsJsxAttributes ObjectFlags = 1 << 11 // Jsx attributes type
+ ObjectFlagsJSLiteral ObjectFlags = 1 << 12 // Object type declared in JS - disables errors on read/write of nonexisting members
+ ObjectFlagsFreshLiteral ObjectFlags = 1 << 13 // Fresh object literal
+ ObjectFlagsArrayLiteral ObjectFlags = 1 << 14 // Originates in an array literal
+ ObjectFlagsPrimitiveUnion ObjectFlags = 1 << 15 // Union of only primitive types
+ ObjectFlagsContainsWideningType ObjectFlags = 1 << 16 // Type is or contains undefined or null widening type
+ ObjectFlagsContainsObjectOrArrayLiteral ObjectFlags = 1 << 17 // Type is or contains object literal type
+ ObjectFlagsNonInferrableType ObjectFlags = 1 << 18 // Type is or contains anyFunctionType or silentNeverType
+ ObjectFlagsCouldContainTypeVariablesComputed ObjectFlags = 1 << 19 // CouldContainTypeVariables flag has been computed
+ ObjectFlagsCouldContainTypeVariables ObjectFlags = 1 << 20 // Type could contain a type variable
+ ObjectFlagsMembersResolved ObjectFlags = 1 << 21 // Members have been resolved
+
+ ObjectFlagsClassOrInterface = ObjectFlagsClass | ObjectFlagsInterface
+ ObjectFlagsRequiresWidening = ObjectFlagsContainsWideningType | ObjectFlagsContainsObjectOrArrayLiteral
+ ObjectFlagsPropagatingFlags = ObjectFlagsContainsWideningType | ObjectFlagsContainsObjectOrArrayLiteral | ObjectFlagsNonInferrableType
+ ObjectFlagsInstantiatedMapped = ObjectFlagsMapped | ObjectFlagsInstantiated
+ // Object flags that uniquely identify the kind of ObjectType
+ ObjectFlagsObjectTypeKindMask = ObjectFlagsClassOrInterface | ObjectFlagsReference | ObjectFlagsTuple | ObjectFlagsAnonymous | ObjectFlagsMapped | ObjectFlagsReverseMapped | ObjectFlagsEvolvingArray
+ // Flags that require TypeFlags.Object
+ ObjectFlagsContainsSpread = 1 << 22 // Object literal contains spread operation
+ ObjectFlagsObjectRestType = 1 << 23 // Originates in object rest declaration
+ ObjectFlagsInstantiationExpressionType = 1 << 24 // Originates in instantiation expression
+ ObjectFlagsSingleSignatureType = 1 << 25 // A single signature type extracted from a potentially broader type
+ ObjectFlagsIsClassInstanceClone = 1 << 26 // Type is a clone of a class instance type
+ // Flags that require TypeFlags.Object and ObjectFlags.Reference
+ ObjectFlagsIdenticalBaseTypeCalculated = 1 << 27 // has had `getSingleBaseForNonAugmentingSubtype` invoked on it already
+ ObjectFlagsIdenticalBaseTypeExists = 1 << 28 // has a defined cachedEquivalentBaseType member
+ // Flags that require TypeFlags.UnionOrIntersection or TypeFlags.Substitution
+ ObjectFlagsIsGenericTypeComputed = 1 << 22 // IsGenericObjectType flag has been computed
+ ObjectFlagsIsGenericObjectType = 1 << 23 // Union or intersection contains generic object type
+ ObjectFlagsIsGenericIndexType = 1 << 24 // Union or intersection contains generic index type
+ ObjectFlagsIsGenericType = ObjectFlagsIsGenericObjectType | ObjectFlagsIsGenericIndexType
+ // Flags that require TypeFlags.Union
+ ObjectFlagsContainsIntersections = 1 << 25 // Union contains intersections
+ ObjectFlagsIsUnknownLikeUnionComputed = 1 << 26 // IsUnknownLikeUnion flag has been computed
+ ObjectFlagsIsUnknownLikeUnion = 1 << 27 // Union of null, undefined, and empty object type
+ // Flags that require TypeFlags.Intersection
+ ObjectFlagsIsNeverIntersectionComputed = 1 << 25 // IsNeverLike flag has been computed
+ ObjectFlagsIsNeverIntersection = 1 << 26 // Intersection reduces to never
+ ObjectFlagsIsConstrainedTypeVariable = 1 << 27 // T & C, where T's constraint and C are primitives, object, or {}
+)
+
+// TypeAlias
+
+type TypeAlias struct {
+ symbol *Symbol
+ typeArguments []*Type
+}
+
+// Type
+
+type Type struct {
+ flags TypeFlags
+ objectFlags ObjectFlags
+ id TypeId
+ symbol *Symbol
+ alias *TypeAlias
+ data TypeData // Type specific data
+}
+
+// Casts for concrete struct types
+
+func (t *Type) IntrinsicType() *IntrinsicTypeData { return t.data.(*IntrinsicTypeData) }
+func (t *Type) LiteralType() *LiteralTypeData { return t.data.(*LiteralTypeData) }
+func (t *Type) UniqueESSymbolType() *UniqueESSymbolTypeData { return t.data.(*UniqueESSymbolTypeData) }
+func (t *Type) InterfaceType() *InterfaceTypeData { return t.data.(*InterfaceTypeData) }
+func (t *Type) TypeReference() *TypeReferenceData { return t.data.(*TypeReferenceData) }
+func (t *Type) AnonymousType() *AnonymousTypeData { return t.data.(*AnonymousTypeData) }
+func (t *Type) TypeParameter() *TypeParameterData { return t.data.(*TypeParameterData) }
+func (t *Type) UnionType() *UnionTypeData { return t.data.(*UnionTypeData) }
+func (t *Type) IntersectionType() *IntersectionTypeData { return t.data.(*IntersectionTypeData) }
+func (t *Type) IndexedAccessType() *IndexedAccessTypeData { return t.data.(*IndexedAccessTypeData) }
+
+// Casts for embedded struct types
+
+func (t *Type) ObjectType() *ObjectTypeBase { return t.data.ObjectType() }
+func (t *Type) ParameterizedType() *ParameterizedTypeBase { return t.data.ParameterizedType() }
+
+// TypeData
+
+type TypeData interface {
+ ObjectType() *ObjectTypeBase
+ ParameterizedType() *ParameterizedTypeBase
+}
+
+// TypeBase
+
+type TypeBase struct{}
+
+func (data *TypeBase) ObjectType() *ObjectTypeBase { return nil }
+func (data *TypeBase) ParameterizedType() *ParameterizedTypeBase { return nil }
+
+// IntrinsicTypeData
+
+type IntrinsicTypeData struct {
+ TypeBase
+ intrinsicName string
+}
+
+// LiteralTypeData
+
+type LiteralTypeData struct {
+ TypeBase
+ value any // string | float64 | bool | PseudoBigInt | nil (computed enum)
+ freshType *Type // Fresh version of type
+ regularType *Type // Regular version of type
+}
+
+type PseudoBigint struct {
+ negative bool
+ base10Value string
+}
+
+// UniqueESSymbolTypeData
+
+type UniqueESSymbolTypeData struct {
+ TypeBase
+ name string
+}
+
+// ObjectTypeBase
+
+type ObjectTypeBase struct {
+ TypeBase
+ members SymbolTable
+ properties []*Symbol
+ callSignatures []*Signature
+ constructSignatures []*Signature
+ indexInfos []*IndexInfo
+}
+
+func (data *ObjectTypeBase) ObjectType() *ObjectTypeBase { return data }
+
+// InstantiatedTypeData
+
+type InstantiatedTypeBase struct {
+ ObjectTypeBase
+ target *Type // Target of instantiated type
+ mapper TypeMapper // Type mapper for instantiated type
+ instantiations map[string]*Type // Map of type instantiations
+}
+
+// ParameterizedTypeData
+
+type ParameterizedTypeBase struct {
+ InstantiatedTypeBase
+ resolvedTypeArguments []*Type
+}
+
+func (data *ParameterizedTypeBase) ParameterizedType() *ParameterizedTypeBase { return data }
+
+// InterfaceType (when generic, serves as reference to instantiation of itself)
+
+type InterfaceTypeData struct {
+ ParameterizedTypeBase
+ typeParameters []*Type // Type parameters
+ outerTypeParameters []*Type // Outer type parameters
+ localTypeParameters []*Type // Local type parameters
+ thisType *Type // The "this" type (nil if none)
+ variances []VarianceFlags
+ baseTypesResolved bool
+ declaredMembersResolved bool
+ resolvedBaseConstructorType *Type
+ resolvedBaseTypes []*Type
+ declaredCallSignatures []*Signature // Declared call signatures
+ declaredConstructSignatures []*Signature // Declared construct signatures
+ declaredIndexInfos []*IndexInfo // Declared index signatures
+ tupleInfo *TupleInfo // Additional data for tuple types
+}
+
+type TupleInfo struct {
+}
+
+// TypeReference (instantiation of a generic type)
+
+type TypeReferenceData struct {
+ ParameterizedTypeBase
+ node *Node // TypeReferenceNode | ArrayTypeNode | TupleTypeNode | nil
+}
+
+// AnonymousType
+
+type AnonymousTypeData struct {
+ InstantiatedTypeBase
+}
+
+// MappedType
+
+type MappedTypeData struct {
+ InstantiatedTypeBase
+ declaration MappedTypeNode
+ typeParameter *Type
+ constraintType *Type
+ nameType *Type
+ templateType *Type
+ modifiersType *Type
+ resolvedApparentType *Type
+ containsError bool
+}
+
+// ReverseMappedType
+
+type ReverseMappedTypeData struct {
+ ObjectTypeBase
+ source *Type
+ mappedType *Type
+ constraintType *Type
+}
+
+// UnionOrIntersectionTypeData
+
+type UnionOrIntersectionTypeBase struct {
+ ObjectTypeBase
+ types []*Type
+ propertyCache SymbolTable
+ propertyCacheWithoutFunctionPropertyAugment SymbolTable
+ resolvedProperties []*Symbol
+ resolvedBaseConstraint *Type
+}
+
+// UnionType
+
+type UnionTypeData struct {
+ UnionOrIntersectionTypeBase
+ resolvedReducedType *Type
+ regularType *Type
+ origin *Type // Denormalized union, intersection, or index type in which union originates
+ keyPropertyName string // Property with unique unit type that exists in every object/intersection in union type
+ constituentMap map[TypeId]*Type // Constituents keyed by unit type discriminants
+}
+
+// IntersectionType
+
+type IntersectionTypeData struct {
+ UnionOrIntersectionTypeBase
+ resolvedApparentType *Type
+}
+
+// TypeParameter
+
+type TypeParameterData struct {
+ TypeBase
+ constraint *Type
+ target *Type
+ mapper TypeMapper
+ isThisType bool
+ resolvedDefaultType *Type
+}
+
+// IndexedAccessType
+
+type IndexedAccessTypeData struct {
+ TypeBase
+ objectType *Type
+ indexType *Type
+ accessFlags AccessFlags // Only includes AccessFlags.Persistent
+}
+
+// TypeMapper
+
+type TypeMapper interface {
+ Map(t *Type) *Type
+}
+
+// Signature
+
+type Signature struct {
+ // !!!
+}
+
+// IndexInfo
+
+type IndexInfo struct {
+ keyType *Type
+ valueType *Type
+ isReadonly bool
+ declaration *IndexSignatureDeclaration
+}
diff --git a/internal/compiler/utilities.go b/internal/compiler/utilities.go
new file mode 100644
index 0000000000..5342c06b3d
--- /dev/null
+++ b/internal/compiler/utilities.go
@@ -0,0 +1,3675 @@
+package compiler
+
+import (
+ "fmt"
+ "maps"
+ "path/filepath"
+ "regexp"
+ "slices"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+
+ "github.com/microsoft/typescript-go/internal/compiler/diagnostics"
+)
+
+// TextPos
+
+type TextPos int32
+
+// TextRange
+
+type TextRange struct {
+ pos TextPos
+ end TextPos
+}
+
+func NewTextRange(pos int, end int) TextRange {
+ return TextRange{pos: TextPos(pos), end: TextPos(end)}
+}
+
+func (t TextRange) Pos() int {
+ return int(t.pos)
+}
+
+func (t TextRange) End() int {
+ return int(t.end)
+}
+
+func (t TextRange) Len() int {
+ return int(t.end - t.pos)
+}
+
+func (t TextRange) ContainsInclusive(pos int) bool {
+ return pos >= int(t.pos) && pos <= int(t.end)
+}
+
+// Pool allocator
+
+type Pool[T any] struct {
+ data []T
+}
+
+func (p *Pool[T]) New() *T {
+ if len(p.data) == cap(p.data) {
+ p.data = make([]T, 0, nextPoolSize(len(p.data)))
+ }
+ index := len(p.data)
+ p.data = p.data[:index+1]
+ return &p.data[index]
+}
+
+// Links store
+
+type LinkStore[K comparable, V any] struct {
+ entries map[K]*V
+ pool Pool[V]
+}
+
+func (s *LinkStore[K, V]) get(key K) *V {
+ value := s.entries[key]
+ if value != nil {
+ return value
+ }
+ if s.entries == nil {
+ s.entries = make(map[K]*V)
+ }
+ value = s.pool.New()
+ s.entries[key] = value
+ return value
+}
+
+// Atomic ids
+
+var nextNodeId atomic.Uint32
+var nextSymbolId atomic.Uint32
+var nextMergeId atomic.Uint32
+
+func getNodeId(node *Node) NodeId {
+ if node.id == 0 {
+ node.id = NodeId(nextNodeId.Add(1))
+ }
+ return node.id
+}
+
+func getSymbolId(symbol *Symbol) SymbolId {
+ if symbol.id == 0 {
+ symbol.id = SymbolId(nextSymbolId.Add(1))
+ }
+ return symbol.id
+}
+
+func getMergeId(symbol *Symbol) MergeId {
+ if symbol.mergeId == 0 {
+ symbol.mergeId = MergeId(nextMergeId.Add(1))
+ }
+ return symbol.mergeId
+}
+
+// Diagnostic
+
+type Diagnostic struct {
+ file *SourceFile
+ loc TextRange
+ code int32
+ category diagnostics.Category
+ message string
+ messageChain []*MessageChain
+ relatedInformation []*Diagnostic
+}
+
+type MessageChain struct {
+ code int32
+ category diagnostics.Category
+ message string
+ messageChain []*MessageChain
+}
+
+func (d *Diagnostic) File() *SourceFile { return d.file }
+func (d *Diagnostic) Loc() TextRange { return d.loc }
+func (d *Diagnostic) Code() int32 { return d.code }
+func (d *Diagnostic) Category() diagnostics.Category { return d.category }
+func (d *Diagnostic) Message() string { return d.message }
+func (d *Diagnostic) RelatedInformation() []*Diagnostic { return d.relatedInformation }
+
+func (d *Diagnostic) SetCategory(category diagnostics.Category) { d.category = category }
+
+func NewDiagnostic(file *SourceFile, loc TextRange, message *diagnostics.Message, args ...any) *Diagnostic {
+ text := message.Message()
+ if len(args) != 0 {
+ text = formatStringFromArgs(text, args)
+ }
+ return &Diagnostic{
+ file: file,
+ loc: loc,
+ code: message.Code(),
+ category: message.Category(),
+ message: text,
+ }
+}
+
+func NewDiagnosticForNode(node *Node, message *diagnostics.Message, args ...any) *Diagnostic {
+ var file *SourceFile
+ var loc TextRange
+ if node != nil {
+ file = getSourceFileOfNode(node)
+ loc = node.loc
+ }
+ return NewDiagnostic(file, loc, message, args...)
+}
+
+func addRelatedInfo(diagnostic *Diagnostic, relatedInformation ...*Diagnostic) *Diagnostic {
+ diagnostic.relatedInformation = append(diagnostic.relatedInformation, relatedInformation...)
+ return diagnostic
+}
+
+type OperatorPrecedence int
+
+const (
+ // Expression:
+ // AssignmentExpression
+ // Expression `,` AssignmentExpression
+ OperatorPrecedenceComma OperatorPrecedence = iota
+ // NOTE: `Spread` is higher than `Comma` due to how it is parsed in |ElementList|
+ // SpreadElement:
+ // `...` AssignmentExpression
+ OperatorPrecedenceSpread
+ // AssignmentExpression:
+ // ConditionalExpression
+ // YieldExpression
+ // ArrowFunction
+ // AsyncArrowFunction
+ // LeftHandSideExpression `=` AssignmentExpression
+ // LeftHandSideExpression AssignmentOperator AssignmentExpression
+ //
+ // NOTE: AssignmentExpression is broken down into several precedences due to the requirements
+ // of the parenthesizer rules.
+ // AssignmentExpression: YieldExpression
+ // YieldExpression:
+ // `yield`
+ // `yield` AssignmentExpression
+ // `yield` `*` AssignmentExpression
+ OperatorPrecedenceYield
+ // AssignmentExpression: LeftHandSideExpression `=` AssignmentExpression
+ // AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression
+ // AssignmentOperator: one of
+ // `*=` `/=` `%=` `+=` `-=` `<<=` `>>=` `>>>=` `&=` `^=` `|=` `**=`
+ OperatorPrecedenceAssignment
+ // NOTE: `Conditional` is considered higher than `Assignment` here, but in reality they have
+ // the same precedence.
+ // AssignmentExpression: ConditionalExpression
+ // ConditionalExpression:
+ // ShortCircuitExpression
+ // ShortCircuitExpression `?` AssignmentExpression `:` AssignmentExpression
+ // ShortCircuitExpression:
+ // LogicalORExpression
+ // CoalesceExpression
+ OperatorPrecedenceConditional
+ // LogicalORExpression:
+ // LogicalANDExpression
+ // LogicalORExpression `||` LogicalANDExpression
+ OperatorPrecedenceLogicalOR
+ // LogicalANDExpression:
+ // BitwiseORExpression
+ // LogicalANDExprerssion `&&` BitwiseORExpression
+ OperatorPrecedenceLogicalAND
+ // BitwiseORExpression:
+ // BitwiseXORExpression
+ // BitwiseORExpression `^` BitwiseXORExpression
+ OperatorPrecedenceBitwiseOR
+ // BitwiseXORExpression:
+ // BitwiseANDExpression
+ // BitwiseXORExpression `^` BitwiseANDExpression
+ OperatorPrecedenceBitwiseXOR
+ // BitwiseANDExpression:
+ // EqualityExpression
+ // BitwiseANDExpression `^` EqualityExpression
+ OperatorPrecedenceBitwiseAND
+ // EqualityExpression:
+ // RelationalExpression
+ // EqualityExpression `==` RelationalExpression
+ // EqualityExpression `!=` RelationalExpression
+ // EqualityExpression `===` RelationalExpression
+ // EqualityExpression `!==` RelationalExpression
+ OperatorPrecedenceEquality
+ // RelationalExpression:
+ // ShiftExpression
+ // RelationalExpression `<` ShiftExpression
+ // RelationalExpression `>` ShiftExpression
+ // RelationalExpression `<=` ShiftExpression
+ // RelationalExpression `>=` ShiftExpression
+ // RelationalExpression `instanceof` ShiftExpression
+ // RelationalExpression `in` ShiftExpression
+ // [+TypeScript] RelationalExpression `as` Type
+ OperatorPrecedenceRelational
+ // ShiftExpression:
+ // AdditiveExpression
+ // ShiftExpression `<<` AdditiveExpression
+ // ShiftExpression `>>` AdditiveExpression
+ // ShiftExpression `>>>` AdditiveExpression
+ OperatorPrecedenceShift
+ // AdditiveExpression:
+ // MultiplicativeExpression
+ // AdditiveExpression `+` MultiplicativeExpression
+ // AdditiveExpression `-` MultiplicativeExpression
+ OperatorPrecedenceAdditive
+ // MultiplicativeExpression:
+ // ExponentiationExpression
+ // MultiplicativeExpression MultiplicativeOperator ExponentiationExpression
+ // MultiplicativeOperator: one of `*`, `/`, `%`
+ OperatorPrecedenceMultiplicative
+ // ExponentiationExpression:
+ // UnaryExpression
+ // UpdateExpression `**` ExponentiationExpression
+ OperatorPrecedenceExponentiation
+ // UnaryExpression:
+ // UpdateExpression
+ // `delete` UnaryExpression
+ // `void` UnaryExpression
+ // `typeof` UnaryExpression
+ // `+` UnaryExpression
+ // `-` UnaryExpression
+ // `~` UnaryExpression
+ // `!` UnaryExpression
+ // AwaitExpression
+ // UpdateExpression: // TODO: Do we need to investigate the precedence here?
+ // `++` UnaryExpression
+ // `--` UnaryExpression
+ OperatorPrecedenceUnary
+ // UpdateExpression:
+ // LeftHandSideExpression
+ // LeftHandSideExpression `++`
+ // LeftHandSideExpression `--`
+ OperatorPrecedenceUpdate
+ // LeftHandSideExpression:
+ // NewExpression
+ // CallExpression
+ // NewExpression:
+ // MemberExpression
+ // `new` NewExpression
+ OperatorPrecedenceLeftHandSide
+ // CallExpression:
+ // CoverCallExpressionAndAsyncArrowHead
+ // SuperCall
+ // ImportCall
+ // CallExpression Arguments
+ // CallExpression `[` Expression `]`
+ // CallExpression `.` IdentifierName
+ // CallExpression TemplateLiteral
+ // MemberExpression:
+ // PrimaryExpression
+ // MemberExpression `[` Expression `]`
+ // MemberExpression `.` IdentifierName
+ // MemberExpression TemplateLiteral
+ // SuperProperty
+ // MetaProperty
+ // `new` MemberExpression Arguments
+ OperatorPrecedenceMember
+ // TODO: JSXElement?
+ // PrimaryExpression:
+ // `this`
+ // IdentifierReference
+ // Literal
+ // ArrayLiteral
+ // ObjectLiteral
+ // FunctionExpression
+ // ClassExpression
+ // GeneratorExpression
+ // AsyncFunctionExpression
+ // AsyncGeneratorExpression
+ // RegularExpressionLiteral
+ // TemplateLiteral
+ // CoverParenthesizedExpressionAndArrowParameterList
+ OperatorPrecedencePrimary
+ // CoalesceExpression:
+ // CoalesceExpressionHead `??` BitwiseORExpression
+ // CoalesceExpressionHead:
+ // CoalesceExpression
+ // BitwiseORExpression
+ OperatorPrecedenceCoalesce = OperatorPrecedenceConditional // NOTE: This is wrong
+ OperatorPrecedenceLowest = OperatorPrecedenceComma
+ OperatorPrecedenceHighest = OperatorPrecedencePrimary
+ // -1 is lower than all other precedences. Returning it will cause binary expression
+ // parsing to stop.
+ OperatorPrecedenceInvalid OperatorPrecedence = -1
+)
+
+func getOperatorPrecedence(nodeKind SyntaxKind, operatorKind SyntaxKind, hasArguments bool) OperatorPrecedence {
+ switch nodeKind {
+ case SyntaxKindCommaListExpression:
+ return OperatorPrecedenceComma
+ case SyntaxKindSpreadElement:
+ return OperatorPrecedenceSpread
+ case SyntaxKindYieldExpression:
+ return OperatorPrecedenceYield
+ case SyntaxKindConditionalExpression:
+ return OperatorPrecedenceConditional
+ case SyntaxKindBinaryExpression:
+ switch operatorKind {
+ case SyntaxKindCommaToken:
+ return OperatorPrecedenceComma
+ case SyntaxKindEqualsToken, SyntaxKindPlusEqualsToken, SyntaxKindMinusEqualsToken, SyntaxKindAsteriskAsteriskEqualsToken,
+ SyntaxKindAsteriskEqualsToken, SyntaxKindSlashEqualsToken, SyntaxKindPercentEqualsToken, SyntaxKindLessThanLessThanEqualsToken,
+ SyntaxKindGreaterThanGreaterThanEqualsToken, SyntaxKindGreaterThanGreaterThanGreaterThanEqualsToken, SyntaxKindAmpersandEqualsToken,
+ SyntaxKindCaretEqualsToken, SyntaxKindBarEqualsToken, SyntaxKindBarBarEqualsToken, SyntaxKindAmpersandAmpersandEqualsToken,
+ SyntaxKindQuestionQuestionEqualsToken:
+ return OperatorPrecedenceAssignment
+ }
+ return getBinaryOperatorPrecedence(operatorKind)
+ // TODO: Should prefix `++` and `--` be moved to the `Update` precedence?
+ case SyntaxKindTypeAssertionExpression, SyntaxKindNonNullExpression, SyntaxKindPrefixUnaryExpression, SyntaxKindTypeOfExpression,
+ SyntaxKindVoidExpression, SyntaxKindDeleteExpression, SyntaxKindAwaitExpression:
+ return OperatorPrecedenceUnary
+ case SyntaxKindPostfixUnaryExpression:
+ return OperatorPrecedenceUpdate
+ case SyntaxKindCallExpression:
+ return OperatorPrecedenceLeftHandSide
+ case SyntaxKindNewExpression:
+ if hasArguments {
+ return OperatorPrecedenceMember
+ }
+ return OperatorPrecedenceLeftHandSide
+ case SyntaxKindTaggedTemplateExpression, SyntaxKindPropertyAccessExpression, SyntaxKindElementAccessExpression, SyntaxKindMetaProperty:
+ return OperatorPrecedenceMember
+ case SyntaxKindAsExpression, SyntaxKindSatisfiesExpression:
+ return OperatorPrecedenceRelational
+ case SyntaxKindThisKeyword, SyntaxKindSuperKeyword, SyntaxKindIdentifier, SyntaxKindPrivateIdentifier, SyntaxKindNullKeyword,
+ SyntaxKindTrueKeyword, SyntaxKindFalseKeyword, SyntaxKindNumericLiteral, SyntaxKindBigintLiteral, SyntaxKindStringLiteral,
+ SyntaxKindArrayLiteralExpression, SyntaxKindObjectLiteralExpression, SyntaxKindFunctionExpression, SyntaxKindArrowFunction,
+ SyntaxKindClassExpression, SyntaxKindRegularExpressionLiteral, SyntaxKindNoSubstitutionTemplateLiteral, SyntaxKindTemplateExpression,
+ SyntaxKindParenthesizedExpression, SyntaxKindOmittedExpression, SyntaxKindJsxElement, SyntaxKindJsxSelfClosingElement, SyntaxKindJsxFragment:
+ return OperatorPrecedencePrimary
+ }
+ return OperatorPrecedenceInvalid
+}
+
+func getBinaryOperatorPrecedence(kind SyntaxKind) OperatorPrecedence {
+ switch kind {
+ case SyntaxKindQuestionQuestionToken:
+ return OperatorPrecedenceCoalesce
+ case SyntaxKindBarBarToken:
+ return OperatorPrecedenceLogicalOR
+ case SyntaxKindAmpersandAmpersandToken:
+ return OperatorPrecedenceLogicalAND
+ case SyntaxKindBarToken:
+ return OperatorPrecedenceBitwiseOR
+ case SyntaxKindCaretToken:
+ return OperatorPrecedenceBitwiseXOR
+ case SyntaxKindAmpersandToken:
+ return OperatorPrecedenceBitwiseAND
+ case SyntaxKindEqualsEqualsToken, SyntaxKindExclamationEqualsToken, SyntaxKindEqualsEqualsEqualsToken, SyntaxKindExclamationEqualsEqualsToken:
+ return OperatorPrecedenceEquality
+ case SyntaxKindLessThanToken, SyntaxKindGreaterThanToken, SyntaxKindLessThanEqualsToken, SyntaxKindGreaterThanEqualsToken,
+ SyntaxKindInstanceOfKeyword, SyntaxKindInKeyword, SyntaxKindAsKeyword, SyntaxKindSatisfiesKeyword:
+ return OperatorPrecedenceRelational
+ case SyntaxKindLessThanLessThanToken, SyntaxKindGreaterThanGreaterThanToken, SyntaxKindGreaterThanGreaterThanGreaterThanToken:
+ return OperatorPrecedenceShift
+ case SyntaxKindPlusToken, SyntaxKindMinusToken:
+ return OperatorPrecedenceAdditive
+ case SyntaxKindAsteriskToken, SyntaxKindSlashToken, SyntaxKindPercentToken:
+ return OperatorPrecedenceMultiplicative
+ case SyntaxKindAsteriskAsteriskToken:
+ return OperatorPrecedenceExponentiation
+ }
+ // -1 is lower than all other precedences. Returning it will cause binary expression
+ // parsing to stop.
+ return OperatorPrecedenceInvalid
+}
+
+var regexps = make(map[string]*regexp.Regexp)
+var regexpMutex sync.Mutex
+
+func makeRegexp(s string) *regexp.Regexp {
+ regexpMutex.Lock()
+ rx, ok := regexps[s]
+ if !ok {
+ rx = regexp.MustCompile(s)
+ regexps[s] = rx
+ }
+ regexpMutex.Unlock()
+ return rx
+}
+
+func formatStringFromArgs(text string, args []any) string {
+ return makeRegexp(`{(\d+)}`).ReplaceAllStringFunc(text, func(match string) string {
+ index, err := strconv.ParseInt(match[1:len(match)-1], 10, 0)
+ if err != nil || int(index) >= len(args) {
+ panic("Invalid formatting placeholder")
+ }
+ return fmt.Sprintf("%v", args[int(index)])
+ })
+}
+
+func filter[T any](slice []T, predicate func(T) bool) []T {
+ var result []T
+ for _, value := range slice {
+ if predicate(value) {
+ result = append(result, value)
+ }
+ }
+ return result
+}
+
+func mapf[T, U any](slice []T, f func(T) U) []U {
+ if len(slice) == 0 {
+ return nil
+ }
+ result := make([]U, len(slice))
+ for i := range slice {
+ result[i] = f(slice[i])
+ }
+ return result
+}
+
+func mapIndex[T, U any](slice []T, f func(T, int) U) []U {
+ if len(slice) == 0 {
+ return nil
+ }
+ result := make([]U, len(slice))
+ for i := range slice {
+ result[i] = f(slice[i], i)
+ }
+ return result
+}
+
+func sameMap[T comparable](slice []T, f func(T) T) ([]T, bool) {
+ for i, value := range slice {
+ mapped := f(value)
+ if mapped != value {
+ result := make([]T, len(slice))
+ copy(result, slice[:i])
+ result[i] = mapped
+ for i, value := range slice[i+1:] {
+ result[i] = f(value)
+ }
+ return result, false
+ }
+ }
+ return slice, true
+}
+
+func some[T any](array []T, predicate func(T) bool) bool {
+ for _, value := range array {
+ if predicate(value) {
+ return true
+ }
+ }
+ return false
+}
+
+func every[T any](array []T, predicate func(T) bool) bool {
+ for _, value := range array {
+ if !predicate(value) {
+ return false
+ }
+ }
+ return true
+}
+
+func forEach[T any](array []T, action func(T)) {
+ for _, value := range array {
+ action(value)
+ }
+}
+
+func insertSorted[T any](slice []T, element T, cmp func(T, T) int) []T {
+ i, _ := slices.BinarySearchFunc(slice, element, cmp)
+ return slices.Insert(slice, i, element)
+}
+
+func firstOrNil[T any](slice []T) T {
+ if len(slice) != 0 {
+ return slice[0]
+ }
+ return *new(T)
+}
+
+func lastOrNil[T any](slice []T) T {
+ if len(slice) != 0 {
+ return slice[len(slice)-1]
+ }
+ return *new(T)
+}
+
+func find[T any](slice []T, predicate func(T) bool) T {
+ for _, value := range slice {
+ if predicate(value) {
+ return value
+ }
+ }
+ return *new(T)
+}
+
+func findLast[T any](slice []T, predicate func(T) bool) T {
+ for i := len(slice) - 1; i >= 0; i-- {
+ value := slice[i]
+ if predicate(value) {
+ return value
+ }
+ }
+ return *new(T)
+}
+
+func findInMap[K comparable, V any](m map[K]V, predicate func(V) bool) V {
+ for _, value := range m {
+ if predicate(value) {
+ return value
+ }
+ }
+ return *new(V)
+}
+
+func concatenate[T any](s1 []T, s2 []T) []T {
+ if len(s2) == 0 {
+ return s1
+ }
+ if len(s1) == 0 {
+ return s2
+ }
+ return slices.Concat(s1, s2)
+}
+
+func boolToTristate(b bool) Tristate {
+ if b {
+ return TSTrue
+ }
+ return TSFalse
+}
+
+func modifierToFlag(token SyntaxKind) ModifierFlags {
+ switch token {
+ case SyntaxKindStaticKeyword:
+ return ModifierFlagsStatic
+ case SyntaxKindPublicKeyword:
+ return ModifierFlagsPublic
+ case SyntaxKindProtectedKeyword:
+ return ModifierFlagsProtected
+ case SyntaxKindPrivateKeyword:
+ return ModifierFlagsPrivate
+ case SyntaxKindAbstractKeyword:
+ return ModifierFlagsAbstract
+ case SyntaxKindAccessorKeyword:
+ return ModifierFlagsAccessor
+ case SyntaxKindExportKeyword:
+ return ModifierFlagsExport
+ case SyntaxKindDeclareKeyword:
+ return ModifierFlagsAmbient
+ case SyntaxKindConstKeyword:
+ return ModifierFlagsConst
+ case SyntaxKindDefaultKeyword:
+ return ModifierFlagsDefault
+ case SyntaxKindAsyncKeyword:
+ return ModifierFlagsAsync
+ case SyntaxKindReadonlyKeyword:
+ return ModifierFlagsReadonly
+ case SyntaxKindOverrideKeyword:
+ return ModifierFlagsOverride
+ case SyntaxKindInKeyword:
+ return ModifierFlagsIn
+ case SyntaxKindOutKeyword:
+ return ModifierFlagsOut
+ case SyntaxKindImmediateKeyword:
+ return ModifierFlagsImmediate
+ case SyntaxKindDecorator:
+ return ModifierFlagsDecorator
+ }
+ return ModifierFlagsNone
+}
+
+func modifiersToFlags(modifierList *Node) ModifierFlags {
+ flags := ModifierFlagsNone
+ if modifierList != nil {
+ for _, modifier := range modifierList.AsModifierList().modifiers {
+ flags |= modifierToFlag(modifier.kind)
+ }
+ }
+ return flags
+}
+
+func nodeIsMissing(node *Node) bool {
+ return node == nil || node.loc.pos == node.loc.end && node.loc.pos >= 0 && node.kind != SyntaxKindEndOfFile
+}
+
+func nodeIsPresent(node *Node) bool {
+ return !nodeIsMissing(node)
+}
+
+func isLeftHandSideExpression(node *Node) bool {
+ return isLeftHandSideExpressionKind(node.kind)
+}
+
+func isLeftHandSideExpressionKind(kind SyntaxKind) bool {
+ switch kind {
+ case SyntaxKindPropertyAccessExpression, SyntaxKindElementAccessExpression, SyntaxKindNewExpression, SyntaxKindCallExpression,
+ SyntaxKindJsxElement, SyntaxKindJsxSelfClosingElement, SyntaxKindJsxFragment, SyntaxKindTaggedTemplateExpression, SyntaxKindArrayLiteralExpression,
+ SyntaxKindParenthesizedExpression, SyntaxKindObjectLiteralExpression, SyntaxKindClassExpression, SyntaxKindFunctionExpression, SyntaxKindIdentifier,
+ SyntaxKindPrivateIdentifier, SyntaxKindRegularExpressionLiteral, SyntaxKindNumericLiteral, SyntaxKindBigintLiteral, SyntaxKindStringLiteral,
+ SyntaxKindNoSubstitutionTemplateLiteral, SyntaxKindTemplateExpression, SyntaxKindFalseKeyword, SyntaxKindNullKeyword, SyntaxKindThisKeyword,
+ SyntaxKindTrueKeyword, SyntaxKindSuperKeyword, SyntaxKindNonNullExpression, SyntaxKindExpressionWithTypeArguments, SyntaxKindMetaProperty,
+ SyntaxKindImportKeyword, SyntaxKindMissingDeclaration:
+ return true
+ }
+ return false
+}
+
+func isAssignmentOperator(token SyntaxKind) bool {
+ return token >= SyntaxKindFirstAssignment && token <= SyntaxKindLastAssignment
+}
+
+func isExpressionWithTypeArguments(node *Node) bool {
+ return node.kind == SyntaxKindExpressionWithTypeArguments
+}
+
+func isNonNullExpression(node *Node) bool {
+ return node.kind == SyntaxKindNonNullExpression
+}
+
+func isStringLiteralLike(node *Node) bool {
+ return node.kind == SyntaxKindStringLiteral || node.kind == SyntaxKindNoSubstitutionTemplateLiteral
+}
+
+func isNumericLiteral(node *Node) bool {
+ return node.kind == SyntaxKindNumericLiteral
+}
+
+func isStringOrNumericLiteralLike(node *Node) bool {
+ return isStringLiteralLike(node) || isNumericLiteral(node)
+}
+
+func isSignedNumericLiteral(node *Node) bool {
+ if node.kind == SyntaxKindPrefixUnaryExpression {
+ node := node.AsPrefixUnaryExpression()
+ return (node.operator == SyntaxKindPlusToken || node.operator == SyntaxKindMinusToken) && isNumericLiteral(node.operand)
+ }
+ return false
+}
+
+func ifElse[T any](b bool, whenTrue T, whenFalse T) T {
+ if b {
+ return whenTrue
+ }
+ return whenFalse
+}
+
+func tokenIsIdentifierOrKeyword(token SyntaxKind) bool {
+ return token >= SyntaxKindIdentifier
+}
+
+func tokenIsIdentifierOrKeywordOrGreaterThan(token SyntaxKind) bool {
+ return token == SyntaxKindGreaterThanToken || tokenIsIdentifierOrKeyword(token)
+}
+
+func getTextOfNode(node *Node) string {
+ return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node)
+}
+
+func getSourceTextOfNodeFromSourceFile(sourceFile *SourceFile, node *Node) string {
+ return getTextOfNodeFromSourceText(sourceFile.text, node)
+}
+
+func getTextOfNodeFromSourceText(sourceText string, node *Node) string {
+ if nodeIsMissing(node) {
+ return ""
+ }
+ text := sourceText[skipTrivia(sourceText, node.Pos()):node.End()]
+ // if (isJSDocTypeExpressionOrChild(node)) {
+ // // strip space + asterisk at line start
+ // text = text.split(/\r\n|\n|\r/).map(line => line.replace(/^\s*\*/, "").trimStart()).join("\n");
+ // }
+ return text
+}
+
+func appendIfUnique[T comparable](array []T, element T) []T {
+ if slices.Contains(array, element) {
+ return array
+ }
+ return append(array, element)
+}
+
+func isAssignmentDeclaration(decl *Node) bool {
+ return isBinaryExpression(decl) || isAccessExpression(decl) || isIdentifier(decl) || isCallExpression(decl)
+}
+
+func isBinaryExpression(node *Node) bool {
+ return node.kind == SyntaxKindBinaryExpression
+}
+
+func isAccessExpression(node *Node) bool {
+ return node.kind == SyntaxKindPropertyAccessExpression || node.kind == SyntaxKindElementAccessExpression
+}
+
+func isInJSFile(node *Node) bool {
+ return node != nil && node.flags&NodeFlagsJavaScriptFile != 0
+}
+
+func isEffectiveModuleDeclaration(node *Node) bool {
+ return isModuleDeclaration(node) || isIdentifier(node)
+}
+
+func isObjectLiteralOrClassExpressionMethodOrAccessor(node *Node) bool {
+ kind := node.kind
+ return (kind == SyntaxKindMethodDeclaration || kind == SyntaxKindGetAccessor || kind == SyntaxKindSetAccessor) &&
+ (node.parent.kind == SyntaxKindObjectLiteralExpression || node.parent.kind == SyntaxKindClassExpression)
+}
+
+func isFunctionLike(node *Node) bool {
+ return node != nil && isFunctionLikeKind(node.kind)
+}
+
+func isFunctionLikeKind(kind SyntaxKind) bool {
+ switch kind {
+ case SyntaxKindMethodSignature, SyntaxKindCallSignature, SyntaxKindJSDocSignature, SyntaxKindConstructSignature, SyntaxKindIndexSignature,
+ SyntaxKindFunctionType, SyntaxKindJSDocFunctionType, SyntaxKindConstructorType:
+ return true
+ }
+ return isFunctionLikeDeclarationKind(kind)
+}
+
+func isFunctionLikeDeclaration(node *Node) bool {
+ return node != nil && isFunctionLikeDeclarationKind(node.kind)
+}
+
+func isFunctionLikeDeclarationKind(kind SyntaxKind) bool {
+ switch kind {
+ case SyntaxKindFunctionDeclaration, SyntaxKindMethodDeclaration, SyntaxKindConstructor, SyntaxKindGetAccessor, SyntaxKindSetAccessor,
+ SyntaxKindFunctionExpression, SyntaxKindArrowFunction:
+ return true
+ }
+ return false
+}
+
+type OuterExpressionKinds int16
+
+const (
+ OEKParentheses OuterExpressionKinds = 1 << 0
+ OEKTypeAssertions OuterExpressionKinds = 1 << 1
+ OEKNonNullAssertions OuterExpressionKinds = 1 << 2
+ OEKExpressionsWithTypeArguments OuterExpressionKinds = 1 << 3
+ OEKExcludeJSDocTypeAssertion = 1 << 4
+ OEKAssertions = OEKTypeAssertions | OEKNonNullAssertions
+ OEKAll = OEKParentheses | OEKAssertions | OEKExpressionsWithTypeArguments
+)
+
+func isOuterExpression(node *Node, kinds OuterExpressionKinds) bool {
+ switch node.kind {
+ case SyntaxKindParenthesizedExpression:
+ return kinds&OEKParentheses != 0 && !(kinds&OEKExcludeJSDocTypeAssertion != 0 && isJSDocTypeAssertion(node))
+ case SyntaxKindTypeAssertionExpression, SyntaxKindAsExpression, SyntaxKindSatisfiesExpression:
+ return kinds&OEKTypeAssertions != 0
+ case SyntaxKindExpressionWithTypeArguments:
+ return kinds&OEKExpressionsWithTypeArguments != 0
+ case SyntaxKindNonNullExpression:
+ return kinds&OEKNonNullAssertions != 0
+ }
+ return false
+}
+
+func getInnerExpression(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindParenthesizedExpression:
+ return node.AsParenthesizedExpression().expression
+ case SyntaxKindTypeAssertionExpression:
+ return node.AsTypeAssertion().expression
+ case SyntaxKindAsExpression:
+ return node.AsAsExpression().expression
+ case SyntaxKindSatisfiesExpression:
+ return node.AsSatisfiesExpression().expression
+ case SyntaxKindExpressionWithTypeArguments:
+ return node.AsExpressionWithTypeArguments().expression
+ case SyntaxKindNonNullExpression:
+ return node.AsNonNullExpression().expression
+ }
+ panic("Unhandled case in getInnerExpression")
+}
+
+func getSymbolFromNode(node *Node) *Symbol {
+ return node.Symbol()
+}
+
+func skipOuterExpressions(node *Node, kinds OuterExpressionKinds) *Node {
+ for isOuterExpression(node, kinds) {
+ node = getInnerExpression(node)
+ }
+ return node
+}
+
+func skipParentheses(node *Node) *Node {
+ return skipOuterExpressions(node, OEKParentheses)
+}
+
+func walkUpParenthesizedTypes(node *Node) *Node {
+ for node != nil && node.kind == SyntaxKindParenthesizedType {
+ node = node.parent
+ }
+ return node
+}
+
+func walkUpParenthesizedExpressions(node *Node) *Node {
+ for node != nil && node.kind == SyntaxKindParenthesizedExpression {
+ node = node.parent
+ }
+ return node
+}
+
+func isJSDocTypeAssertion(node *Node) bool {
+ return false // !!!
+}
+
+// Return true if the given identifier is classified as an IdentifierName
+func isIdentifierName(node *Node) bool {
+ parent := node.parent
+ switch parent.kind {
+ case SyntaxKindPropertyDeclaration, SyntaxKindPropertySignature, SyntaxKindMethodDeclaration, SyntaxKindMethodSignature, SyntaxKindGetAccessor,
+ SyntaxKindSetAccessor, SyntaxKindEnumMember, SyntaxKindPropertyAssignment, SyntaxKindPropertyAccessExpression:
+ return parent.Name() == node
+ case SyntaxKindQualifiedName:
+ return parent.AsQualifiedName().right == node
+ case SyntaxKindBindingElement:
+ return parent.AsBindingElement().propertyName == node
+ case SyntaxKindImportSpecifier:
+ return parent.AsImportSpecifier().propertyName == node
+ case SyntaxKindExportSpecifier, SyntaxKindJsxAttribute, SyntaxKindJsxSelfClosingElement, SyntaxKindJsxOpeningElement, SyntaxKindJsxClosingElement:
+ return true
+ }
+ return false
+}
+
+func getSourceFileOfNode(node *Node) *SourceFile {
+ for {
+ if node == nil {
+ return nil
+ }
+ if node.kind == SyntaxKindSourceFile {
+ return node.data.(*SourceFile)
+ }
+ node = node.parent
+ }
+}
+
+/** @internal */
+func getErrorRangeForNode(sourceFile *SourceFile, node *Node) TextRange {
+ errorNode := node
+ switch node.kind {
+ case SyntaxKindSourceFile:
+ pos := skipTrivia(sourceFile.text, 0)
+ if pos == len(sourceFile.text) {
+ return NewTextRange(0, 0)
+ }
+ return getRangeOfTokenAtPosition(sourceFile, pos)
+ // This list is a work in progress. Add missing node kinds to improve their error spans
+ case SyntaxKindVariableDeclaration, SyntaxKindBindingElement, SyntaxKindClassDeclaration, SyntaxKindClassExpression, SyntaxKindInterfaceDeclaration,
+ SyntaxKindModuleDeclaration, SyntaxKindEnumDeclaration, SyntaxKindEnumMember, SyntaxKindFunctionDeclaration, SyntaxKindFunctionExpression,
+ SyntaxKindMethodDeclaration, SyntaxKindGetAccessor, SyntaxKindSetAccessor, SyntaxKindTypeAliasDeclaration, SyntaxKindPropertyDeclaration,
+ SyntaxKindPropertySignature, SyntaxKindNamespaceImport:
+ errorNode = getNameOfDeclaration(node)
+ case SyntaxKindArrowFunction:
+ return getErrorRangeForArrowFunction(sourceFile, node)
+ case SyntaxKindCaseClause:
+ case SyntaxKindDefaultClause:
+ start := skipTrivia(sourceFile.text, node.Pos())
+ end := node.End()
+ statements := node.data.(*CaseOrDefaultClause).statements
+ if len(statements) != 0 {
+ end = statements[0].Pos()
+ }
+ return NewTextRange(start, end)
+ case SyntaxKindReturnStatement, SyntaxKindYieldExpression:
+ pos := skipTrivia(sourceFile.text, node.Pos())
+ return getRangeOfTokenAtPosition(sourceFile, pos)
+ case SyntaxKindSatisfiesExpression:
+ pos := skipTrivia(sourceFile.text, node.AsSatisfiesExpression().expression.End())
+ return getRangeOfTokenAtPosition(sourceFile, pos)
+ case SyntaxKindConstructor:
+ scanner := getScannerForSourceFile(sourceFile, node.Pos())
+ start := scanner.tokenStart
+ for scanner.token != SyntaxKindConstructorKeyword && scanner.token != SyntaxKindStringLiteral && scanner.token != SyntaxKindEndOfFile {
+ scanner.Scan()
+ }
+ return NewTextRange(start, scanner.pos)
+ // !!!
+ // case SyntaxKindJSDocSatisfiesTag:
+ // pos := skipTrivia(sourceFile.text, node.tagName.pos)
+ // return getRangeOfTokenAtPosition(sourceFile, pos)
+ }
+ if errorNode == nil {
+ // If we don't have a better node, then just set the error on the first token of
+ // construct.
+ return getRangeOfTokenAtPosition(sourceFile, node.Pos())
+ }
+ pos := errorNode.Pos()
+ if !nodeIsMissing(errorNode) {
+ pos = skipTrivia(sourceFile.text, pos)
+ }
+ return NewTextRange(pos, errorNode.End())
+}
+
+func getErrorRangeForArrowFunction(sourceFile *SourceFile, node *Node) TextRange {
+ pos := skipTrivia(sourceFile.text, node.Pos())
+ body := node.AsArrowFunction().body
+ if body != nil && body.kind == SyntaxKindBlock {
+ startLine, _ := GetLineAndCharacterOfPosition(sourceFile, body.Pos())
+ endLine, _ := GetLineAndCharacterOfPosition(sourceFile, body.End())
+ if startLine < endLine {
+ // The arrow function spans multiple lines,
+ // make the error span be the first line, inclusive.
+ return NewTextRange(pos, getEndLinePosition(sourceFile, startLine))
+ }
+ }
+ return NewTextRange(pos, node.End())
+}
+
+func getContainingClass(node *Node) *Node {
+ return findAncestor(node.parent, isClassLike)
+}
+
+func findAncestor(node *Node, callback func(*Node) bool) *Node {
+ for node != nil {
+ result := callback(node)
+ if result {
+ return node
+ }
+ node = node.parent
+ }
+ return nil
+}
+
+type FindAncestorResult int32
+
+const (
+ FindAncestorFalse FindAncestorResult = iota
+ FindAncestorTrue
+ FindAncestorQuit
+)
+
+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 isClassLike(node *Node) bool {
+ return node != nil && (node.kind == SyntaxKindClassDeclaration || node.kind == SyntaxKindClassExpression)
+}
+
+func declarationNameToString(name *Node) string {
+ if !exists(name) || name.Pos() == name.End() {
+ return "(Missing)"
+ }
+ return getTextOfNode(name)
+}
+
+func isExternalModule(file *SourceFile) bool {
+ return file.externalModuleIndicator != nil
+}
+
+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 SyntaxKindComputedPropertyName:
+ if includeClassComputedPropertyName && isClassLike(node.parent.parent) {
+ return node
+ }
+ node = node.parent.parent
+ case SyntaxKindDecorator:
+ if node.parent.kind == SyntaxKindParameter && 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 SyntaxKindArrowFunction:
+ if includeArrowFunctions {
+ return node
+ }
+ case SyntaxKindFunctionDeclaration, SyntaxKindFunctionExpression, SyntaxKindModuleDeclaration, SyntaxKindClassStaticBlockDeclaration,
+ SyntaxKindPropertyDeclaration, SyntaxKindPropertySignature, SyntaxKindMethodDeclaration, SyntaxKindMethodSignature, SyntaxKindConstructor,
+ SyntaxKindGetAccessor, SyntaxKindSetAccessor, SyntaxKindCallSignature, SyntaxKindConstructSignature, SyntaxKindIndexSignature,
+ SyntaxKindEnumDeclaration, SyntaxKindSourceFile:
+ return node
+ }
+ }
+}
+
+func isClassElement(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindConstructor, SyntaxKindPropertyDeclaration, SyntaxKindMethodDeclaration, SyntaxKindGetAccessor, SyntaxKindSetAccessor,
+ SyntaxKindIndexSignature, SyntaxKindClassStaticBlockDeclaration, SyntaxKindSemicolonClassElement:
+ return true
+ }
+ return false
+}
+
+func isPartOfTypeQuery(node *Node) bool {
+ for node.kind == SyntaxKindQualifiedName || node.kind == SyntaxKindIdentifier {
+ node = node.parent
+ }
+ return node.kind == SyntaxKindTypeQuery
+}
+
+func getModifierFlags(node *Node) ModifierFlags {
+ modifiers := node.Modifiers()
+ if modifiers != nil {
+ return modifiers.AsModifierList().modifierFlags
+ }
+ return ModifierFlagsNone
+}
+
+func getNodeFlags(node *Node) NodeFlags {
+ return node.flags
+}
+
+func hasSyntacticModifier(node *Node, flags ModifierFlags) bool {
+ return getModifierFlags(node)&flags != 0
+}
+
+func hasAccessorModifier(node *Node) bool {
+ return hasSyntacticModifier(node, ModifierFlagsAccessor)
+}
+
+func hasStaticModifier(node *Node) bool {
+ return hasSyntacticModifier(node, ModifierFlagsStatic)
+}
+
+func getEffectiveModifierFlags(node *Node) ModifierFlags {
+ return getModifierFlags(node) // !!! Handle JSDoc
+}
+
+func hasEffectiveModifier(node *Node, flags ModifierFlags) bool {
+ return getEffectiveModifierFlags(node)&flags != 0
+}
+
+func getImmediatelyInvokedFunctionExpression(fn *Node) *Node {
+ if fn.kind == SyntaxKindFunctionExpression || fn.kind == SyntaxKindArrowFunction {
+ prev := fn
+ parent := fn.parent
+ for parent.kind == SyntaxKindParenthesizedExpression {
+ prev = parent
+ parent = parent.parent
+ }
+ if parent.kind == SyntaxKindCallExpression && parent.AsCallExpression().expression == prev {
+ return parent
+ }
+ }
+ return nil
+}
+
+// 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 getElementOrPropertyAccessArgumentExpressionOrName(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindPropertyAccessExpression:
+ return node.AsPropertyAccessExpression().name
+ case SyntaxKindElementAccessExpression:
+ arg := skipParentheses(node.AsElementAccessExpression().argumentExpression)
+ if isStringOrNumericLiteralLike(arg) {
+ return arg
+ }
+ return node
+ }
+ panic("Unhandled case in getElementOrPropertyAccessArgumentExpressionOrName")
+}
+
+func getAccessedExpression(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindPropertyAccessExpression:
+ return node.AsPropertyAccessExpression().expression
+ case SyntaxKindElementAccessExpression:
+ return node.AsElementAccessExpression().expression
+ case SyntaxKindCallExpression:
+ return node.AsCallExpression().expression
+ case SyntaxKindParenthesizedExpression:
+ return node.AsParenthesizedExpression().expression
+ case SyntaxKindNonNullExpression:
+ return node.AsNonNullExpression().expression
+ case SyntaxKindTypeAssertionExpression:
+ return node.AsTypeAssertion().expression
+ case SyntaxKindAsExpression:
+ return node.AsAsExpression().expression
+ }
+ panic("Unhandled case in getAccessedExpression")
+}
+
+func getQuestionDotToken(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindPropertyAccessExpression:
+ return node.AsPropertyAccessExpression().questionDotToken
+ case SyntaxKindElementAccessExpression:
+ return node.AsElementAccessExpression().questionDotToken
+ case SyntaxKindCallExpression:
+ return node.AsCallExpression().questionDotToken
+ }
+ panic("Unhandled case in getQuestionDotToken")
+}
+
+/**
+ * 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 SyntaxKindComputedPropertyName:
+ expr = name.AsComputedPropertyName().expression
+ case SyntaxKindElementAccessExpression:
+ expr = skipParentheses(name.AsElementAccessExpression().argumentExpression)
+ default:
+ return false
+ }
+ return !isStringOrNumericLiteralLike(expr) && !isSignedNumericLiteral(expr)
+}
+
+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 getNonAssignedNameOfDeclaration(declaration *Node) *Node {
+ switch declaration.kind {
+ case SyntaxKindBinaryExpression:
+ if isFunctionPropertyAssignment(declaration) {
+ return getElementOrPropertyAccessArgumentExpressionOrName(declaration.AsBinaryExpression().left)
+ }
+ return nil
+ case SyntaxKindExportAssignment:
+ 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 SyntaxKindPropertyAssignment:
+ return parent.AsPropertyAssignment().name
+ case SyntaxKindBindingElement:
+ return parent.AsBindingElement().name
+ case SyntaxKindBinaryExpression:
+ if node == parent.AsBinaryExpression().right {
+ left := parent.AsBinaryExpression().left
+ switch left.kind {
+ case SyntaxKindIdentifier:
+ return left
+ case SyntaxKindPropertyAccessExpression:
+ return left.AsPropertyAccessExpression().name
+ case SyntaxKindElementAccessExpression:
+ arg := skipParentheses(left.AsElementAccessExpression().argumentExpression)
+ if isStringOrNumericLiteralLike(arg) {
+ return arg
+ }
+ }
+ }
+ case SyntaxKindVariableDeclaration:
+ name := parent.AsVariableDeclaration().name
+ if isIdentifier(name) {
+ return name
+ }
+ }
+ }
+ return nil
+}
+
+func isFunctionPropertyAssignment(node *Node) bool {
+ if node.kind == SyntaxKindBinaryExpression {
+ expr := node.AsBinaryExpression()
+ if expr.operatorToken.kind == SyntaxKindEqualsToken {
+ switch expr.left.kind {
+ case SyntaxKindPropertyAccessExpression:
+ // F.id = expr
+ return isIdentifier(expr.left.AsPropertyAccessExpression().expression) && isIdentifier(expr.left.AsPropertyAccessExpression().name)
+ case SyntaxKindElementAccessExpression:
+ // F[xxx] = expr
+ return isIdentifier(expr.left.AsElementAccessExpression().expression)
+ }
+ }
+ }
+ return false
+}
+
+func isAssignmentExpression(node *Node, excludeCompoundAssignment bool) bool {
+ if node.kind == SyntaxKindBinaryExpression {
+ expr := node.AsBinaryExpression()
+ return (expr.operatorToken.kind == SyntaxKindEqualsToken || !excludeCompoundAssignment && isAssignmentOperator(expr.operatorToken.kind)) &&
+ isLeftHandSideExpression(expr.left)
+ }
+ return false
+}
+
+func isBlockOrCatchScoped(declaration *Node) bool {
+ return getCombinedNodeFlags(declaration)&NodeFlagsBlockScoped != 0 || isCatchClauseVariableDeclarationOrBindingElement(declaration)
+}
+
+func isCatchClauseVariableDeclarationOrBindingElement(declaration *Node) bool {
+ node := getRootDeclaration(declaration)
+ return node.kind == SyntaxKindVariableDeclaration && node.parent.kind == SyntaxKindCatchClause
+}
+
+func isAmbientModule(node *Node) bool {
+ return isModuleDeclaration(node) && (node.AsModuleDeclaration().name.kind == SyntaxKindStringLiteral || isGlobalScopeAugmentation(node))
+}
+
+func isGlobalScopeAugmentation(node *Node) bool {
+ return node.flags&NodeFlagsGlobalAugmentation != 0
+}
+
+func isPropertyNameLiteral(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindIdentifier, SyntaxKindStringLiteral, SyntaxKindNoSubstitutionTemplateLiteral, SyntaxKindNumericLiteral:
+ return true
+ }
+ return false
+}
+
+func getTextOfIdentifierOrLiteral(node *Node) string {
+ switch node.kind {
+ case SyntaxKindIdentifier:
+ return node.AsIdentifier().text
+ case SyntaxKindPrivateIdentifier:
+ return node.AsPrivateIdentifier().text
+ case SyntaxKindStringLiteral:
+ return node.AsStringLiteral().text
+ case SyntaxKindNumericLiteral:
+ return node.AsNumericLiteral().text
+ case SyntaxKindBigintLiteral:
+ return node.AsBigintLiteral().text
+ case SyntaxKindNoSubstitutionTemplateLiteral:
+ return node.AsNoSubstitutionTemplateLiteral().text
+ // case isJsxNamespacedName(node):
+ // return getTextOfJsxNamespacedName(node)
+ }
+ panic("Unhandled case in getTextOfIdentifierOrLiteral")
+}
+
+func isMemberName(node *Node) bool {
+ return node.kind == SyntaxKindIdentifier || node.kind == SyntaxKindPrivateIdentifier
+}
+
+func setParent(child *Node, parent *Node) {
+ if child != nil {
+ child.parent = parent
+ }
+}
+
+func setParentInChildren(node *Node) {
+ node.ForEachChild(func(child *Node) bool {
+ child.parent = node
+ setParentInChildren(child)
+ return false
+ })
+}
+
+func getCombinedFlags[T ~uint32](node *Node, getFlags func(*Node) T) T {
+ node = getRootDeclaration(node)
+ flags := getFlags(node)
+ if node.kind == SyntaxKindVariableDeclaration {
+ node = node.parent
+ }
+ if node != nil && node.kind == SyntaxKindVariableDeclarationList {
+ flags |= getFlags(node)
+ node = node.parent
+ }
+ if node != nil && node.kind == SyntaxKindVariableStatement {
+ flags |= getFlags(node)
+ }
+ return flags
+}
+
+func getCombinedModifierFlags(node *Node) ModifierFlags {
+ return getCombinedFlags(node, getModifierFlags)
+}
+
+func getCombinedNodeFlags(node *Node) NodeFlags {
+ return getCombinedFlags(node, getNodeFlags)
+}
+
+func isBindingPattern(node *Node) bool {
+ return node != nil && (node.kind == SyntaxKindArrayBindingPattern || node.kind == SyntaxKindObjectBindingPattern)
+}
+
+func isParameterPropertyDeclaration(node *Node, parent *Node) bool {
+ return isParameter(node) && hasSyntacticModifier(node, ModifierFlagsParameterPropertyModifier) && parent.kind == SyntaxKindConstructor
+}
+
+/**
+ * Like {@link isVariableDeclarationInitializedToRequire} but allows things like `require("...").foo.bar` or `require("...")["baz"]`.
+ */
+func isVariableDeclarationInitializedToBareOrAccessedRequire(node *Node) bool {
+ return isVariableDeclarationInitializedWithRequireHelper(node, true /*allowAccessedRequire*/)
+}
+
+func isVariableDeclarationInitializedWithRequireHelper(node *Node, allowAccessedRequire bool) bool {
+ if node.kind == SyntaxKindVariableDeclaration && node.AsVariableDeclaration().initializer != nil {
+ initializer := node.AsVariableDeclaration().initializer
+ if allowAccessedRequire {
+ initializer = getLeftmostAccessExpression(initializer)
+ }
+ return isRequireCall(initializer, true /*requireStringLiteralLikeArgument*/)
+ }
+ return false
+}
+
+func getLeftmostAccessExpression(expr *Node) *Node {
+ for isAccessExpression(expr) {
+ expr = getAccessedExpression(expr)
+ }
+ return expr
+}
+
+func isRequireCall(node *Node, requireStringLiteralLikeArgument bool) bool {
+ if isCallExpression(node) {
+ callExpression := node.AsCallExpression()
+ if len(callExpression.arguments) == 1 {
+ if isIdentifier(callExpression.expression) && callExpression.expression.AsIdentifier().text == "require" {
+ return !requireStringLiteralLikeArgument || isStringLiteralLike(callExpression.arguments[0])
+ }
+ }
+ }
+ return false
+}
+
+/**
+ * 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 == SyntaxKindParameter
+}
+
+func getRootDeclaration(node *Node) *Node {
+ for node.kind == SyntaxKindBindingElement {
+ node = node.parent.parent
+ }
+ return node
+}
+
+func isExternalOrCommonJsModule(file *SourceFile) bool {
+ return file.externalModuleIndicator != nil
+}
+
+func isAutoAccessorPropertyDeclaration(node *Node) bool {
+ return isPropertyDeclaration(node) && hasAccessorModifier(node)
+}
+
+func isAsyncFunction(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindFunctionDeclaration, SyntaxKindFunctionExpression, SyntaxKindArrowFunction, SyntaxKindMethodDeclaration:
+ data := node.BodyData()
+ return data.body != nil && data.asteriskToken == nil && hasSyntacticModifier(node, ModifierFlagsAsync)
+ }
+ return false
+}
+
+func isObjectLiteralMethod(node *Node) bool {
+ return node != nil && node.kind == SyntaxKindMethodDeclaration && node.parent.kind == SyntaxKindObjectLiteralExpression
+}
+
+func symbolName(symbol *Symbol) string {
+ if symbol.valueDeclaration != nil && isPrivateIdentifierClassElementDeclaration(symbol.valueDeclaration) {
+ return symbol.valueDeclaration.Name().AsPrivateIdentifier().text
+ }
+ return symbol.name
+}
+
+func isStaticPrivateIdentifierProperty(s *Symbol) bool {
+ return s.valueDeclaration != nil && isPrivateIdentifierClassElementDeclaration(s.valueDeclaration) && isStatic(s.valueDeclaration)
+}
+
+func isPrivateIdentifierClassElementDeclaration(node *Node) bool {
+ return (isPropertyDeclaration(node) || isMethodOrAccessor(node)) && isPrivateIdentifier(node.Name())
+}
+
+func isMethodOrAccessor(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindMethodDeclaration, SyntaxKindGetAccessor, SyntaxKindSetAccessor:
+ return true
+ }
+ return false
+}
+
+func isFunctionLikeOrClassStaticBlockDeclaration(node *Node) bool {
+ return node != nil && (isFunctionLikeKind(node.kind) || isClassStaticBlockDeclaration(node))
+}
+
+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 SyntaxKindSourceFile:
+ return isExternalModule(node.parent.AsSourceFile())
+ case SyntaxKindModuleBlock:
+ grandParent := node.parent.parent
+ return isAmbientModule(grandParent) && isSourceFile(grandParent.parent) && !isExternalModule(grandParent.parent.AsSourceFile())
+ }
+ return false
+}
+
+type Pattern struct {
+ text string
+ starIndex int // -1 for exact match
+}
+
+func isValidPattern(pattern Pattern) bool {
+ return pattern.starIndex == -1 || pattern.starIndex < len(pattern.text)
+}
+
+func tryParsePattern(pattern string) Pattern {
+ starIndex := strings.Index(pattern, "*")
+ if starIndex == -1 || !strings.Contains(pattern[starIndex+1:], "*") {
+ return Pattern{text: pattern, starIndex: starIndex}
+ }
+ return Pattern{}
+}
+
+func isDeclarationStatementKind(kind SyntaxKind) bool {
+ switch kind {
+ case SyntaxKindFunctionDeclaration, SyntaxKindMissingDeclaration, SyntaxKindClassDeclaration, SyntaxKindInterfaceDeclaration,
+ SyntaxKindTypeAliasDeclaration, SyntaxKindEnumDeclaration, SyntaxKindModuleDeclaration, SyntaxKindImportDeclaration,
+ SyntaxKindImportEqualsDeclaration, SyntaxKindExportDeclaration, SyntaxKindExportAssignment, SyntaxKindNamespaceExportDeclaration:
+ return true
+ }
+ return false
+}
+
+func isDeclarationStatement(node *Node) bool {
+ return isDeclarationStatementKind(node.kind)
+}
+
+func isStatementKindButNotDeclarationKind(kind SyntaxKind) bool {
+ switch kind {
+ case SyntaxKindBreakStatement, SyntaxKindContinueStatement, SyntaxKindDebuggerStatement, SyntaxKindDoStatement, SyntaxKindExpressionStatement,
+ SyntaxKindEmptyStatement, SyntaxKindForInStatement, SyntaxKindForOfStatement, SyntaxKindForStatement, SyntaxKindIfStatement,
+ SyntaxKindLabeledStatement, SyntaxKindReturnStatement, SyntaxKindSwitchStatement, SyntaxKindThrowStatement, SyntaxKindTryStatement,
+ SyntaxKindVariableStatement, SyntaxKindWhileStatement, SyntaxKindWithStatement, SyntaxKindNotEmittedStatement:
+ return true
+ }
+ return false
+}
+
+func isStatementButNotDeclaration(node *Node) bool {
+ return isStatementKindButNotDeclarationKind(node.kind)
+}
+
+func isStatement(node *Node) bool {
+ kind := node.kind
+ return isStatementKindButNotDeclarationKind(kind) || isDeclarationStatementKind(kind) || isBlockStatement(node)
+}
+
+func isBlockStatement(node *Node) bool {
+ if node.kind != SyntaxKindBlock {
+ return false
+ }
+ if node.parent != nil && (node.parent.kind == SyntaxKindTryStatement || node.parent.kind == SyntaxKindCatchClause) {
+ return false
+ }
+ return !isFunctionBlock(node)
+}
+
+func isFunctionBlock(node *Node) bool {
+ return node != nil && node.kind == SyntaxKindBlock && isFunctionLike(node.parent)
+}
+
+func shouldPreserveConstEnums(options *CompilerOptions) bool {
+ return options.PreserveConstEnums == TSTrue || options.IsolatedModules == TSTrue
+}
+
+func exportAssignmentIsAlias(node *Node) bool {
+ return isAliasableExpression(getExportAssignmentExpression(node))
+}
+
+func getExportAssignmentExpression(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindExportAssignment:
+ return node.AsExportAssignment().expression
+ case SyntaxKindBinaryExpression:
+ return node.AsBinaryExpression().right
+ }
+ panic("Unhandled case in getExportAssignmentExpression")
+}
+
+func isAliasableExpression(e *Node) bool {
+ return isEntityNameExpression(e) || isClassExpression(e)
+}
+
+func isEmptyObjectLiteral(expression *Node) bool {
+ return expression.kind == SyntaxKindObjectLiteralExpression && len(expression.AsObjectLiteralExpression().properties) == 0
+}
+
+func isFunctionSymbol(symbol *Symbol) bool {
+ d := symbol.valueDeclaration
+ return d != nil && (isFunctionDeclaration(d) || isVariableDeclaration(d) && isFunctionLike(d.AsVariableDeclaration().initializer))
+}
+
+func isLogicalOrCoalescingAssignmentOperator(token SyntaxKind) bool {
+ return token == SyntaxKindBarBarEqualsToken || token == SyntaxKindAmpersandAmpersandEqualsToken || token == SyntaxKindQuestionQuestionEqualsToken
+}
+
+func isLogicalOrCoalescingAssignmentExpression(expr *Node) bool {
+ return isBinaryExpression(expr) && isLogicalOrCoalescingAssignmentOperator(expr.AsBinaryExpression().operatorToken.kind)
+}
+
+func isLogicalOrCoalescingBinaryOperator(token SyntaxKind) bool {
+ return isBinaryLogicalOperator(token) || token == SyntaxKindQuestionQuestionToken
+}
+
+func isLogicalOrCoalescingBinaryExpression(expr *Node) bool {
+ return isBinaryExpression(expr) && isLogicalOrCoalescingBinaryOperator(expr.AsBinaryExpression().operatorToken.kind)
+}
+
+func isBinaryLogicalOperator(token SyntaxKind) bool {
+ return token == SyntaxKindBarBarToken || token == SyntaxKindAmpersandAmpersandToken
+}
+
+/**
+ * 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 *Node) bool {
+ parent := node.parent
+ return !isOptionalChain(parent) || // cases 1, 2, and 3
+ isOptionalChainRoot(parent) || // case 4
+ node != getAccessedExpression(parent) // case 5
+}
+
+func isNullishCoalesce(node *Node) bool {
+ return node.kind == SyntaxKindBinaryExpression && node.AsBinaryExpression().operatorToken.kind == SyntaxKindQuestionQuestionToken
+}
+
+func isDottedName(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindIdentifier, SyntaxKindThisKeyword, SyntaxKindSuperKeyword, SyntaxKindMetaProperty:
+ return true
+ case SyntaxKindPropertyAccessExpression, SyntaxKindParenthesizedExpression:
+ return isDottedName(getAccessedExpression(node))
+ }
+ return false
+}
+
+func unusedLabelIsError(options *CompilerOptions) bool {
+ return options.AllowUnusedLabels == TSFalse
+}
+
+func unreachableCodeIsError(options *CompilerOptions) bool {
+ return options.AllowUnreachableCode == TSFalse
+}
+
+func isDestructuringAssignment(node *Node) bool {
+ if isAssignmentExpression(node, true /*excludeCompoundAssignment*/) {
+ kind := node.AsBinaryExpression().left.kind
+ return kind == SyntaxKindObjectLiteralExpression || kind == SyntaxKindArrayLiteralExpression
+ }
+ return false
+}
+
+func isTopLevelLogicalExpression(node *Node) bool {
+ for isParenthesizedExpression(node.parent) || isPrefixUnaryExpression(node.parent) && node.parent.AsPrefixUnaryExpression().operator == SyntaxKindExclamationToken {
+ node = node.parent
+ }
+ return !isStatementCondition(node) && !isLogicalExpression(node.parent) && !(isOptionalChain(node.parent) && getAccessedExpression(node.parent) == node)
+}
+
+func isStatementCondition(node *Node) bool {
+ switch node.parent.kind {
+ case SyntaxKindIfStatement:
+ return node.parent.AsIfStatement().expression == node
+ case SyntaxKindWhileStatement:
+ return node.parent.AsWhileStatement().expression == node
+ case SyntaxKindDoStatement:
+ return node.parent.AsDoStatement().expression == node
+ case SyntaxKindForStatement:
+ return node.parent.AsForStatement().condition == node
+ case SyntaxKindConditionalExpression:
+ return node.parent.AsConditionalExpression().condition == node
+ }
+ return false
+}
+
+type AssignmentKind int32
+
+const (
+ AssignmentKindNone AssignmentKind = iota
+ AssignmentKindDefinite
+ AssignmentKindCompound
+)
+
+type AssignmentTarget = Node // BinaryExpression | PrefixUnaryExpression | PostfixUnaryExpression | ForInOrOfStatement
+
+func getAssignmentTargetKind(node *Node) AssignmentKind {
+ target := getAssignmentTarget(node)
+ if target == nil {
+ return AssignmentKindNone
+ }
+ switch target.kind {
+ case SyntaxKindBinaryExpression:
+ binaryOperator := target.AsBinaryExpression().operatorToken.kind
+ if binaryOperator == SyntaxKindEqualsToken || isLogicalOrCoalescingAssignmentOperator(binaryOperator) {
+ return AssignmentKindDefinite
+ }
+ return AssignmentKindCompound
+ case SyntaxKindPrefixUnaryExpression, SyntaxKindPostfixUnaryExpression:
+ return AssignmentKindCompound
+ case SyntaxKindForInStatement, SyntaxKindForOfStatement:
+ return AssignmentKindDefinite
+ }
+ panic("Unhandled case in getAssignmentTargetKind")
+}
+
+// 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 SyntaxKindBinaryExpression:
+ if isAssignmentOperator(parent.AsBinaryExpression().operatorToken.kind) && parent.AsBinaryExpression().left == node {
+ return parent
+ }
+ return nil
+ case SyntaxKindPrefixUnaryExpression:
+ if parent.AsPrefixUnaryExpression().operator == SyntaxKindPlusPlusToken || parent.AsPrefixUnaryExpression().operator == SyntaxKindMinusMinusToken {
+ return parent
+ }
+ return nil
+ case SyntaxKindPostfixUnaryExpression:
+ if parent.AsPostfixUnaryExpression().operator == SyntaxKindPlusPlusToken || parent.AsPostfixUnaryExpression().operator == SyntaxKindMinusMinusToken {
+ return parent
+ }
+ return nil
+ case SyntaxKindForInStatement, SyntaxKindForOfStatement:
+ if parent.AsForInOrOfStatement().initializer == node {
+ return parent
+ }
+ return nil
+ case SyntaxKindParenthesizedExpression, SyntaxKindArrayLiteralExpression, SyntaxKindSpreadElement, SyntaxKindNonNullExpression:
+ node = parent
+ case SyntaxKindSpreadAssignment:
+ node = parent.parent
+ case SyntaxKindShorthandPropertyAssignment:
+ if parent.AsShorthandPropertyAssignment().name != node {
+ return nil
+ }
+ node = parent.parent
+ case SyntaxKindPropertyAssignment:
+ if parent.AsPropertyAssignment().name == node {
+ return nil
+ }
+ node = parent.parent
+ default:
+ return nil
+ }
+ }
+}
+
+func isInCompoundLikeAssignment(node *Node) bool {
+ target := getAssignmentTarget(node)
+ return target != nil && isAssignmentExpression(target /*excludeCompoundAssignment*/, true) && isCompoundLikeAssignment(target)
+}
+
+func isCompoundLikeAssignment(assignment *Node) bool {
+ right := skipParentheses(assignment.AsBinaryExpression().right)
+ return right.kind == SyntaxKindBinaryExpression && isShiftOperatorOrHigher(right.AsBinaryExpression().operatorToken.kind)
+}
+
+func isPushOrUnshiftIdentifier(node *Node) bool {
+ text := node.AsIdentifier().text
+ return text == "push" || text == "unshift"
+}
+
+func isBooleanLiteral(node *Node) bool {
+ return node.kind == SyntaxKindTrueKeyword || node.kind == SyntaxKindFalseKeyword
+}
+
+func isOptionalChain(node *Node) bool {
+ kind := node.kind
+ return node.flags&NodeFlagsOptionalChain != 0 && (kind == SyntaxKindPropertyAccessExpression ||
+ kind == SyntaxKindElementAccessExpression || kind == SyntaxKindCallExpression || kind == SyntaxKindNonNullExpression)
+}
+
+func isOptionalChainRoot(node *Node) bool {
+ return isOptionalChain(node) && !isNonNullExpression(node) && getQuestionDotToken(node) != nil
+}
+
+/**
+ * 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) && getAccessedExpression(node.parent) == node
+}
+
+func isEntityNameExpression(node *Node) bool {
+ return node.kind == SyntaxKindIdentifier || isPropertyAccessEntityNameExpression(node)
+}
+
+func isPropertyAccessEntityNameExpression(node *Node) bool {
+ if node.kind == SyntaxKindPropertyAccessExpression {
+ expr := node.AsPropertyAccessExpression()
+ return expr.name.kind == SyntaxKindIdentifier && isEntityNameExpression(expr.expression)
+ }
+ return false
+}
+
+func isPrologueDirective(node *Node) bool {
+ return node.kind == SyntaxKindExpressionStatement && node.AsExpressionStatement().expression.kind == SyntaxKindStringLiteral
+}
+
+func nextPoolSize(size int) int {
+ switch {
+ case size < 16:
+ return 16
+ case size < 256:
+ return size * 2
+ }
+ return size
+}
+
+func getStatementsOfBlock(block *Node) []*Statement {
+ switch block.kind {
+ case SyntaxKindBlock:
+ return block.AsBlock().statements
+ case SyntaxKindModuleBlock:
+ return block.AsModuleBlock().statements
+ case SyntaxKindSourceFile:
+ return block.AsSourceFile().statements
+ }
+ panic("Unhandled case in getStatementsOfBlock")
+}
+
+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
+ return some(declarations, func(d *Node) bool { return nodeHasName(d, id) })
+ }
+ return false
+}
+
+func isImportMeta(node *Node) bool {
+ if node.kind == SyntaxKindMetaProperty {
+ return node.AsMetaProperty().keywordToken == SyntaxKindImportKeyword && node.AsMetaProperty().name.AsIdentifier().text == "meta"
+ }
+ return false
+}
+
+func lastElement[T any](slice []T) T {
+ if len(slice) != 0 {
+ return slice[len(slice)-1]
+ }
+ return *new(T)
+}
+
+func ensureScriptKind(fileName string, scriptKind ScriptKind) ScriptKind {
+ // Using scriptKind as a condition handles both:
+ // - 'scriptKind' is unspecified and thus it is `undefined`
+ // - 'scriptKind' is set and it is `Unknown` (0)
+ // If the 'scriptKind' is 'undefined' or 'Unknown' then we attempt
+ // to get the ScriptKind from the file name. If it cannot be resolved
+ // from the file name then the default 'TS' script kind is returned.
+ if scriptKind == ScriptKindUnknown {
+ scriptKind = getScriptKindFromFileName(fileName)
+ }
+ if scriptKind == ScriptKindUnknown {
+ scriptKind = ScriptKindTS
+ }
+ return scriptKind
+}
+
+const (
+ ExtensionTs = ".ts"
+ ExtensionTsx = ".tsx"
+ ExtensionDts = ".d.ts"
+ ExtensionJs = ".js"
+ ExtensionJsx = ".jsx"
+ ExtensionJson = ".json"
+ ExtensionTsBuildInfo = ".tsbuildinfo"
+ ExtensionMjs = ".mjs"
+ ExtensionMts = ".mts"
+ ExtensionDmts = ".d.mts"
+ ExtensionCjs = ".cjs"
+ ExtensionCts = ".cts"
+ ExtensionDcts = ".d.cts"
+)
+
+var supportedDeclarationExtensions = []string{ExtensionDts, ExtensionDcts, ExtensionDmts}
+
+func getScriptKindFromFileName(fileName string) ScriptKind {
+ dotPos := strings.LastIndex(fileName, ".")
+ if dotPos >= 0 {
+ switch strings.ToLower(fileName[dotPos:]) {
+ case ExtensionJs, ExtensionCjs, ExtensionMjs:
+ return ScriptKindJS
+ case ExtensionJsx:
+ return ScriptKindJSX
+ case ExtensionTs, ExtensionCts, ExtensionMts:
+ return ScriptKindTS
+ case ExtensionTsx:
+ return ScriptKindTSX
+ case ExtensionJson:
+ return ScriptKindJSON
+ }
+ }
+ return ScriptKindUnknown
+}
+
+func getLanguageVariant(scriptKind ScriptKind) LanguageVariant {
+ switch scriptKind {
+ case ScriptKindTSX, ScriptKindJSX, ScriptKindJS, ScriptKindJSON:
+ // .tsx and .jsx files are treated as jsx language variant.
+ return LanguageVariantJSX
+ }
+ return LanguageVariantStandard
+}
+
+func getEmitScriptTarget(options *CompilerOptions) ScriptTarget {
+ if options.Target != ScriptTargetNone {
+ return options.Target
+ }
+ return ScriptTargetES5
+}
+
+func getEmitModuleKind(options *CompilerOptions) ModuleKind {
+ if options.ModuleKind != ModuleKindNone {
+ return options.ModuleKind
+ }
+ if options.Target >= ScriptTargetES2015 {
+ return ModuleKindES2015
+ }
+ return ModuleKindCommonJS
+}
+
+func getEmitModuleResolutionKind(options *CompilerOptions) ModuleResolutionKind {
+ if options.ModuleResolution != ModuleResolutionKindUnknown {
+ return options.ModuleResolution
+ }
+ switch getEmitModuleKind(options) {
+ case ModuleKindCommonJS:
+ return ModuleResolutionKindNode10
+ case ModuleKindNode16:
+ return ModuleResolutionKindNode16
+ case ModuleKindNodeNext:
+ return ModuleResolutionKindNodeNext
+ case ModuleKindPreserve:
+ return ModuleResolutionKindBundler
+ }
+ return ModuleResolutionKindClassic
+}
+
+func getESModuleInterop(options *CompilerOptions) bool {
+ if options.ESModuleInterop != TSUnknown {
+ return options.ESModuleInterop == TSTrue
+ }
+ switch getEmitModuleKind(options) {
+ case ModuleKindNode16:
+ case ModuleKindNodeNext:
+ case ModuleKindPreserve:
+ return true
+ }
+ return false
+
+}
+func getAllowSyntheticDefaultImports(options *CompilerOptions) bool {
+ if options.AllowSyntheticDefaultImports != TSUnknown {
+ return options.AllowSyntheticDefaultImports == TSTrue
+ }
+ return getESModuleInterop(options) ||
+ getEmitModuleKind(options) == ModuleKindSystem ||
+ getEmitModuleResolutionKind(options) == ModuleResolutionKindBundler
+}
+
+type DiagnosticsCollection struct {
+ fileDiagnostics map[string][]*Diagnostic
+ nonFileDiagnostics []*Diagnostic
+}
+
+func (c *DiagnosticsCollection) add(diagnostic *Diagnostic) {
+ if diagnostic.file != nil {
+ fileName := diagnostic.file.fileName
+ if c.fileDiagnostics == nil {
+ c.fileDiagnostics = make(map[string][]*Diagnostic)
+ }
+ c.fileDiagnostics[fileName] = insertSorted(c.fileDiagnostics[fileName], diagnostic, compareDiagnostics)
+ } else {
+ c.nonFileDiagnostics = insertSorted(c.nonFileDiagnostics, diagnostic, compareDiagnostics)
+ }
+}
+
+func (c *DiagnosticsCollection) lookup(diagnostic *Diagnostic) *Diagnostic {
+ var diagnostics []*Diagnostic
+ if diagnostic.file != nil {
+ diagnostics = c.fileDiagnostics[diagnostic.file.fileName]
+ } else {
+ diagnostics = c.nonFileDiagnostics
+ }
+ if i, ok := slices.BinarySearchFunc(diagnostics, diagnostic, compareDiagnostics); ok {
+ return diagnostics[i]
+ }
+ return nil
+}
+
+func (c *DiagnosticsCollection) GetGlobalDiagnostics() []*Diagnostic {
+ return c.nonFileDiagnostics
+}
+
+func (c *DiagnosticsCollection) GetDiagnosticsForFile(fileName string) []*Diagnostic {
+ return c.fileDiagnostics[fileName]
+}
+
+func (c *DiagnosticsCollection) GetDiagnostics() []*Diagnostic {
+ fileNames := slices.Collect(maps.Keys(c.fileDiagnostics))
+ slices.Sort(fileNames)
+ diagnostics := c.nonFileDiagnostics
+ for _, fileName := range fileNames {
+ diagnostics = append(diagnostics, c.fileDiagnostics[fileName]...)
+ }
+ return diagnostics
+}
+
+func sortAndDeduplicateDiagnostics(diagnostics []*Diagnostic) []*Diagnostic {
+ result := slices.Clone(diagnostics)
+ slices.SortFunc(result, compareDiagnostics)
+ return slices.CompactFunc(result, equalDiagnostics)
+}
+
+func equalDiagnostics(d1, d2 *Diagnostic) bool {
+ return getDiagnosticPath(d1) == getDiagnosticPath(d2) &&
+ d1.loc == d2.loc &&
+ d1.code == d2.code &&
+ d1.message == d2.message &&
+ slices.EqualFunc(d1.messageChain, d2.messageChain, equalMessageChain) &&
+ slices.EqualFunc(d1.relatedInformation, d2.relatedInformation, equalDiagnostics)
+}
+
+func equalMessageChain(c1, c2 *MessageChain) bool {
+ return c1.code == c2.code &&
+ c1.message == c2.message &&
+ slices.EqualFunc(c1.messageChain, c2.messageChain, equalMessageChain)
+}
+
+func compareDiagnostics(d1, d2 *Diagnostic) int {
+ c := strings.Compare(getDiagnosticPath(d1), getDiagnosticPath(d2))
+ if c != 0 {
+ return c
+ }
+ c = int(d1.loc.pos) - int(d2.loc.pos)
+ if c != 0 {
+ return c
+ }
+ c = int(d1.loc.end) - int(d2.loc.end)
+ if c != 0 {
+ return c
+ }
+ c = int(d1.code) - int(d2.code)
+ if c != 0 {
+ return c
+ }
+ c = strings.Compare(d1.message, d2.message)
+ if c != 0 {
+ return c
+ }
+ c = compareMessageChainSize(d1.messageChain, d2.messageChain)
+ if c != 0 {
+ return c
+ }
+ c = compareMessageChainContent(d1.messageChain, d2.messageChain)
+ if c != 0 {
+ return c
+ }
+ return compareRelatedInfo(d1.relatedInformation, d2.relatedInformation)
+}
+
+func compareMessageChainSize(c1, c2 []*MessageChain) int {
+ c := len(c2) - len(c1)
+ if c != 0 {
+ return c
+ }
+ for i := range c1 {
+ c = compareMessageChainSize(c1[i].messageChain, c2[i].messageChain)
+ if c != 0 {
+ return c
+ }
+ }
+ return 0
+}
+
+func compareMessageChainContent(c1, c2 []*MessageChain) int {
+ for i := range c1 {
+ c := strings.Compare(c1[i].message, c2[i].message)
+ if c != 0 {
+ return c
+ }
+ if c1[i].messageChain != nil {
+ c = compareMessageChainContent(c1[i].messageChain, c2[i].messageChain)
+ if c != 0 {
+ return c
+ }
+ }
+ }
+ return 0
+}
+
+func compareRelatedInfo(r1, r2 []*Diagnostic) int {
+ c := len(r2) - len(r1)
+ if c != 0 {
+ return c
+ }
+ for i := range r1 {
+ c = compareDiagnostics(r1[i], r2[i])
+ if c != 0 {
+ return c
+ }
+ }
+ return 0
+}
+
+func getDiagnosticPath(d *Diagnostic) string {
+ if d.file != nil {
+ return d.file.path
+ }
+ return ""
+}
+
+func isConstAssertion(location *Node) bool {
+ switch location.kind {
+ case SyntaxKindAsExpression:
+ return isConstTypeReference(location.AsAsExpression().typeNode)
+ case SyntaxKindTypeAssertionExpression:
+ return isConstTypeReference(location.AsTypeAssertion().typeNode)
+ }
+ return false
+}
+
+func isConstTypeReference(node *Node) bool {
+ if node.kind == SyntaxKindTypeReference {
+ ref := node.AsTypeReference()
+ return ref.typeArguments == nil && isIdentifier(ref.typeName) && ref.typeName.AsIdentifier().text == "const"
+ }
+ return false
+}
+
+func isModuleOrEnumDeclaration(node *Node) bool {
+ return node.kind == SyntaxKindModuleDeclaration || node.kind == SyntaxKindEnumDeclaration
+}
+
+func getLocalsOfNode(node *Node) SymbolTable {
+ data := node.LocalsContainerData()
+ if data != nil {
+ return data.locals
+ }
+ return nil
+}
+
+func getBodyOfNode(node *Node) *Node {
+ bodyData := node.BodyData()
+ if bodyData != nil {
+ return bodyData.body
+ }
+ return nil
+}
+
+func isGlobalSourceFile(node *Node) bool {
+ return node.kind == SyntaxKindSourceFile && !isExternalOrCommonJsModule(node.AsSourceFile())
+}
+
+func isParameterLikeOrReturnTag(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindParameter, SyntaxKindTypeParameter, SyntaxKindJSDocParameterTag, SyntaxKindJSDocReturnTag:
+ return true
+ }
+ return false
+}
+
+func getEmitStandardClassFields(options *CompilerOptions) bool {
+ return options.UseDefineForClassFields != TSFalse && getEmitScriptTarget(options) >= ScriptTargetES2022
+}
+
+func isTypeNodeKind(kind SyntaxKind) bool {
+ switch kind {
+ case SyntaxKindAnyKeyword, SyntaxKindUnknownKeyword, SyntaxKindNumberKeyword, SyntaxKindBigIntKeyword, SyntaxKindObjectKeyword,
+ SyntaxKindBooleanKeyword, SyntaxKindStringKeyword, SyntaxKindSymbolKeyword, SyntaxKindVoidKeyword, SyntaxKindUndefinedKeyword,
+ SyntaxKindNeverKeyword, SyntaxKindIntrinsicKeyword, SyntaxKindExpressionWithTypeArguments, SyntaxKindJSDocAllType, SyntaxKindJSDocUnknownType,
+ SyntaxKindJSDocNullableType, SyntaxKindJSDocNonNullableType, SyntaxKindJSDocOptionalType, SyntaxKindJSDocFunctionType, SyntaxKindJSDocVariadicType:
+ return true
+ }
+ return kind >= SyntaxKindFirstTypeNode && kind <= SyntaxKindLastTypeNode
+}
+
+func isTypeNode(node *Node) bool {
+ return isTypeNodeKind(node.kind)
+}
+
+func getLocalSymbolForExportDefault(symbol *Symbol) *Symbol {
+ if !isExportDefaultSymbol(symbol) || len(symbol.declarations) == 0 {
+ return nil
+ }
+ for _, decl := range symbol.declarations {
+ localSymbol := decl.LocalSymbol()
+ if localSymbol != nil {
+ return localSymbol
+ }
+ }
+ return nil
+}
+
+func isExportDefaultSymbol(symbol *Symbol) bool {
+ return symbol != nil && len(symbol.declarations) > 0 && hasSyntacticModifier(symbol.declarations[0], ModifierFlagsDefault)
+}
+
+func getDeclarationOfKind(symbol *Symbol, kind SyntaxKind) *Node {
+ for _, declaration := range symbol.declarations {
+ if declaration.kind == kind {
+ return declaration
+ }
+ }
+ return nil
+}
+
+func getIsolatedModules(options *CompilerOptions) bool {
+ return options.IsolatedModules == TSTrue || options.VerbatimModuleSyntax == TSTrue
+}
+
+func findConstructorDeclaration(node *Node) *Node {
+ for _, member := range node.ClassLikeData().members {
+ if isConstructorDeclaration(member) && nodeIsPresent(member.AsConstructorDeclaration().body) {
+ return member
+ }
+ }
+ return nil
+}
+
+type NameResolver struct {
+ compilerOptions *CompilerOptions
+ getSymbolOfDeclaration func(node *Node) *Symbol
+ error func(location *Node, message *diagnostics.Message, args ...any) *Diagnostic
+ globals SymbolTable
+ argumentsSymbol *Symbol
+ requireSymbol *Symbol
+ lookup func(symbols SymbolTable, name string, meaning SymbolFlags) *Symbol
+ setRequiresScopeChangeCache func(node *Node, value Tristate)
+ getRequiresScopeChangeCache func(node *Node) Tristate
+ onPropertyWithInvalidInitializer func(location *Node, name string, declaration *Node, result *Symbol) bool
+ onFailedToResolveSymbol func(location *Node, name string, meaning SymbolFlags, nameNotFoundMessage *diagnostics.Message)
+ onSuccessfullyResolvedSymbol func(location *Node, result *Symbol, meaning SymbolFlags, lastLocation *Node, associatedDeclarationForContainingInitializerOrBindingName *Node, withinDeferredContext bool)
+}
+
+func (r *NameResolver) resolve(location *Node, name string, meaning SymbolFlags, nameNotFoundMessage *diagnostics.Message, isUse bool, excludeGlobals bool) *Symbol {
+ var result *Symbol
+ var lastLocation *Node
+ var lastSelfReferenceLocation *Node
+ var propertyWithInvalidInitializer *Node
+ var associatedDeclarationForContainingInitializerOrBindingName *Node
+ var withinDeferredContext bool
+ var grandparent *Node
+ originalLocation := location // needed for did-you-mean error reporting, which gathers candidates starting from the original location
+ nameIsConst := name == "const"
+loop:
+ for location != nil {
+ if nameIsConst && isConstAssertion(location) {
+ // `const` in an `as const` has no symbol, but issues no error because there is no *actual* lookup of the type
+ // (it refers to the constant type of the expression instead)
+ return nil
+ }
+ if isModuleOrEnumDeclaration(location) && lastLocation != nil && location.Name() == lastLocation {
+ // If lastLocation is the name of a namespace or enum, skip the parent since it will have is own locals that could
+ // conflict.
+ lastLocation = location
+ location = location.parent
+ }
+ locals := getLocalsOfNode(location)
+ // Locals of a source file are not in scope (because they get merged into the global symbol table)
+ if locals != nil && !isGlobalSourceFile(location) {
+ result = r.lookup(locals, name, meaning)
+ if result != nil {
+ useResult := true
+ if isFunctionLike(location) && lastLocation != nil && lastLocation != getBodyOfNode(location) {
+ // symbol lookup restrictions for function-like declarations
+ // - Type parameters of a function are in scope in the entire function declaration, including the parameter
+ // list and return type. However, local types are only in scope in the function body.
+ // - parameters are only in the scope of function body
+ // This restriction does not apply to JSDoc comment types because they are parented
+ // at a higher level than type parameters would normally be
+ if meaning&result.flags&SymbolFlagsType != 0 && lastLocation.kind != SyntaxKindJSDoc {
+ useResult = result.flags&SymbolFlagsTypeParameter != 0 && (lastLocation.flags&NodeFlagsSynthesized != 0 ||
+ lastLocation == location.FunctionLikeData().returnType ||
+ isParameterLikeOrReturnTag(lastLocation))
+ }
+ if meaning&result.flags&SymbolFlagsVariable != 0 {
+ // expression inside parameter will lookup as normal variable scope when targeting es2015+
+ if r.useOuterVariableScopeInParameter(result, location, lastLocation) {
+ useResult = false
+ } else if result.flags&SymbolFlagsFunctionScopedVariable != 0 {
+ // parameters are visible only inside function body, parameter list and return type
+ // technically for parameter list case here we might mix parameters and variables declared in function,
+ // however it is detected separately when checking initializers of parameters
+ // to make sure that they reference no variables declared after them.
+ useResult = lastLocation.kind == SyntaxKindParameter ||
+ lastLocation.flags&NodeFlagsSynthesized != 0 ||
+ lastLocation == location.FunctionLikeData().returnType && findAncestor(result.valueDeclaration, isParameter) != nil
+ }
+ }
+ } else if location.kind == SyntaxKindConditionalType {
+ // A type parameter declared using 'infer T' in a conditional type is visible only in
+ // the true branch of the conditional type.
+ useResult = lastLocation == location.AsConditionalTypeNode().trueType
+ }
+ if useResult {
+ break loop
+ }
+ result = nil
+ }
+ }
+ withinDeferredContext = withinDeferredContext || getIsDeferredContext(location, lastLocation)
+ switch location.kind {
+ case SyntaxKindSourceFile:
+ if !isExternalOrCommonJsModule(location.AsSourceFile()) {
+ break
+ }
+ fallthrough
+ case SyntaxKindModuleDeclaration:
+ moduleExports := r.getSymbolOfDeclaration(location).exports
+ if isSourceFile(location) || (isModuleDeclaration(location) && location.flags&NodeFlagsAmbient != 0 && !isGlobalScopeAugmentation(location)) {
+ // It's an external module. First see if the module has an export default and if the local
+ // name of that export default matches.
+ result = moduleExports[InternalSymbolNameDefault]
+ if result != nil {
+ localSymbol := getLocalSymbolForExportDefault(result)
+ if localSymbol != nil && result.flags&meaning != 0 && localSymbol.name == name {
+ break loop
+ }
+ result = nil
+ }
+ // Because of module/namespace merging, a module's exports are in scope,
+ // yet we never want to treat an export specifier as putting a member in scope.
+ // Therefore, if the name we find is purely an export specifier, it is not actually considered in scope.
+ // Two things to note about this:
+ // 1. We have to check this without calling getSymbol. The problem with calling getSymbol
+ // on an export specifier is that it might find the export specifier itself, and try to
+ // resolve it as an alias. This will cause the checker to consider the export specifier
+ // a circular alias reference when it might not be.
+ // 2. We check === SymbolFlags.Alias in order to check that the symbol is *purely*
+ // an alias. If we used &, we'd be throwing out symbols that have non alias aspects,
+ // which is not the desired behavior.
+ moduleExport := moduleExports[name]
+ if moduleExport != nil && moduleExport.flags == SymbolFlagsAlias && (getDeclarationOfKind(moduleExport, SyntaxKindExportSpecifier) != nil || getDeclarationOfKind(moduleExport, SyntaxKindNamespaceExport) != nil) {
+ break
+ }
+ }
+ if name != InternalSymbolNameDefault {
+ result = r.lookup(moduleExports, name, meaning&SymbolFlagsModuleMember)
+ if result != nil {
+ break loop
+ }
+ }
+ case SyntaxKindEnumDeclaration:
+ result = r.lookup(r.getSymbolOfDeclaration(location).exports, name, meaning&SymbolFlagsEnumMember)
+ if result != nil {
+ if nameNotFoundMessage != nil && getIsolatedModules(r.compilerOptions) && location.flags&NodeFlagsAmbient == 0 && getSourceFileOfNode(location) != getSourceFileOfNode(result.valueDeclaration) {
+ isolatedModulesLikeFlagName := ifElse(r.compilerOptions.VerbatimModuleSyntax == TSTrue, "verbatimModuleSyntax", "isolatedModules")
+ r.error(originalLocation, diagnostics.Cannot_access_0_from_another_file_without_qualification_when_1_is_enabled_Use_2_instead,
+ name, isolatedModulesLikeFlagName, r.getSymbolOfDeclaration(location).name+"."+name)
+ }
+ break loop
+ }
+ case SyntaxKindPropertyDeclaration:
+ if !isStatic(location) {
+ ctor := findConstructorDeclaration(location.parent)
+ if ctor != nil && ctor.AsConstructorDeclaration().locals != nil {
+ if r.lookup(ctor.AsConstructorDeclaration().locals, name, meaning&SymbolFlagsValue) != nil {
+ // Remember the property node, it will be used later to report appropriate error
+ propertyWithInvalidInitializer = location
+ }
+ }
+ }
+ case SyntaxKindClassDeclaration, SyntaxKindClassExpression, SyntaxKindInterfaceDeclaration:
+ result = r.lookup(r.getSymbolOfDeclaration(location).members, name, meaning&SymbolFlagsType)
+ if result != nil {
+ if !isTypeParameterSymbolDeclaredInContainer(result, location) {
+ // ignore type parameters not declared in this container
+ result = nil
+ break
+ }
+ if lastLocation != nil && isStatic(lastLocation) {
+ // TypeScript 1.0 spec (April 2014): 3.4.1
+ // The scope of a type parameter extends over the entire declaration with which the type
+ // parameter list is associated, with the exception of static member declarations in classes.
+ if nameNotFoundMessage != nil {
+ r.error(originalLocation, diagnostics.Static_members_cannot_reference_class_type_parameters)
+ }
+ return nil
+ }
+ break loop
+ }
+ if isClassExpression(location) && meaning&SymbolFlagsClass != 0 {
+ className := location.AsClassExpression().name
+ if className != nil && name == className.AsIdentifier().text {
+ result = location.AsClassExpression().symbol
+ break loop
+ }
+ }
+ case SyntaxKindExpressionWithTypeArguments:
+ if lastLocation == location.AsExpressionWithTypeArguments().expression && isHeritageClause(location.parent) && location.parent.AsHeritageClause().token == SyntaxKindExtendsKeyword {
+ container := location.parent.parent
+ if isClassLike(container) {
+ result = r.lookup(r.getSymbolOfDeclaration(container).members, name, meaning&SymbolFlagsType)
+ if result != nil {
+ if nameNotFoundMessage != nil {
+ r.error(originalLocation, diagnostics.Base_class_expressions_cannot_reference_class_type_parameters)
+ }
+ return nil
+ }
+ }
+ }
+ // It is not legal to reference a class's own type parameters from a computed property name that
+ // belongs to the class. For example:
+ //
+ // function foo() { return '' }
+ // class C { // <-- Class's own type parameter T
+ // [foo()]() { } // <-- Reference to T from class's own computed property
+ // }
+ case SyntaxKindComputedPropertyName:
+ grandparent = location.parent.parent
+ if isClassLike(grandparent) || isInterfaceDeclaration(grandparent) {
+ // A reference to this grandparent's type parameters would be an error
+ result = r.lookup(r.getSymbolOfDeclaration(grandparent).members, name, meaning&SymbolFlagsType)
+ if result != nil {
+ if nameNotFoundMessage != nil {
+ r.error(originalLocation, diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type)
+ }
+ return nil
+ }
+ }
+ case SyntaxKindArrowFunction:
+ // when targeting ES6 or higher there is no 'arguments' in an arrow function
+ // for lower compile targets the resolved symbol is used to emit an error
+ if getEmitScriptTarget(r.compilerOptions) >= ScriptTargetES2015 {
+ break
+ }
+ fallthrough
+ case SyntaxKindMethodDeclaration, SyntaxKindConstructor, SyntaxKindGetAccessor, SyntaxKindSetAccessor, SyntaxKindFunctionDeclaration:
+ if meaning&SymbolFlagsVariable != 0 && name == "arguments" {
+ result = r.argumentsSymbol
+ break loop
+ }
+ case SyntaxKindFunctionExpression:
+ if meaning&SymbolFlagsVariable != 0 && name == "arguments" {
+ result = r.argumentsSymbol
+ break loop
+ }
+ if meaning&SymbolFlagsFunction != 0 {
+ functionName := location.AsFunctionExpression().name
+ if functionName != nil && name == functionName.AsIdentifier().text {
+ result = location.AsFunctionExpression().symbol
+ break loop
+ }
+ }
+ case SyntaxKindDecorator:
+ // Decorators are resolved at the class declaration. Resolving at the parameter
+ // or member would result in looking up locals in the method.
+ //
+ // function y() {}
+ // class C {
+ // method(@y x, y) {} // <-- decorator y should be resolved at the class declaration, not the parameter.
+ // }
+ //
+ if location.parent != nil && location.parent.kind == SyntaxKindParameter {
+ location = location.parent
+ }
+ // function y() {}
+ // class C {
+ // @y method(x, y) {} // <-- decorator y should be resolved at the class declaration, not the method.
+ // }
+ //
+ // class Decorators are resolved outside of the class to avoid referencing type parameters of that class.
+ //
+ // type T = number;
+ // declare function y(x: T): any;
+ // @param(1 as T) // <-- T should resolve to the type alias outside of class C
+ // class C {}
+ if location.parent != nil && (isClassElement(location.parent) || location.parent.kind == SyntaxKindClassDeclaration) {
+ location = location.parent
+ }
+ case SyntaxKindParameter:
+ parameterDeclaration := location.AsParameterDeclaration()
+ if lastLocation != nil && (lastLocation == parameterDeclaration.initializer ||
+ lastLocation == parameterDeclaration.name && isBindingPattern(lastLocation)) {
+ if associatedDeclarationForContainingInitializerOrBindingName == nil {
+ associatedDeclarationForContainingInitializerOrBindingName = location
+ }
+ }
+ case SyntaxKindBindingElement:
+ bindingElement := location.AsBindingElement()
+ if lastLocation != nil && (lastLocation == bindingElement.initializer ||
+ lastLocation == bindingElement.name && isBindingPattern(lastLocation)) {
+ if isPartOfParameterDeclaration(location) && associatedDeclarationForContainingInitializerOrBindingName == nil {
+ associatedDeclarationForContainingInitializerOrBindingName = location
+ }
+ }
+ case SyntaxKindInferType:
+ if meaning&SymbolFlagsTypeParameter != 0 {
+ parameterName := location.AsInferTypeNode().typeParameter.AsTypeParameter().name
+ if parameterName != nil && name == parameterName.AsIdentifier().text {
+ result = location.AsInferTypeNode().typeParameter.AsTypeParameter().symbol
+ break loop
+ }
+ }
+ case SyntaxKindExportSpecifier:
+ exportSpecifier := location.AsExportSpecifier()
+ if lastLocation != nil && lastLocation == exportSpecifier.propertyName && location.parent.parent.AsExportDeclaration().moduleSpecifier != nil {
+ location = location.parent.parent.parent
+ }
+ }
+ if isSelfReferenceLocation(location, lastLocation) {
+ lastSelfReferenceLocation = location
+ }
+ lastLocation = location
+ switch {
+ // case isJSDocTemplateTag(location):
+ // location = getEffectiveContainerForJSDocTemplateTag(location.(*JSDocTemplateTag))
+ // if location == nil {
+ // location = location.parent
+ // }
+ // case isJSDocParameterTag(location) || isJSDocReturnTag(location):
+ // location = getHostSignatureFromJSDoc(location)
+ // if location == nil {
+ // location = location.parent
+ // }
+ default:
+ location = location.parent
+ }
+ }
+ // We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`.
+ // If `result === lastSelfReferenceLocation.symbol`, that means that we are somewhere inside `lastSelfReferenceLocation` looking up a name, and resolving to `lastLocation` itself.
+ // That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used.
+ if isUse && result != nil && (lastSelfReferenceLocation == nil || result != lastSelfReferenceLocation.Symbol()) {
+ // !!! result.isReferenced |= meaning
+ }
+ if result == nil {
+ if !excludeGlobals {
+ result = r.lookup(r.globals, name, meaning)
+ }
+ }
+ if nameNotFoundMessage != nil {
+ if propertyWithInvalidInitializer != nil && r.onPropertyWithInvalidInitializer(originalLocation, name, propertyWithInvalidInitializer, result) {
+ return nil
+ }
+ if result == nil {
+ r.onFailedToResolveSymbol(originalLocation, name, meaning, nameNotFoundMessage)
+ } else {
+ r.onSuccessfullyResolvedSymbol(originalLocation, result, meaning, lastLocation, associatedDeclarationForContainingInitializerOrBindingName, withinDeferredContext)
+ }
+ }
+ return result
+}
+
+func (r *NameResolver) useOuterVariableScopeInParameter(result *Symbol, location *Node, lastLocation *Node) bool {
+ if isParameter(lastLocation) {
+ body := getBodyOfNode(location)
+ if body != nil && result.valueDeclaration != nil && result.valueDeclaration.Pos() >= body.Pos() && result.valueDeclaration.End() <= body.End() {
+ // check for several cases where we introduce temporaries that require moving the name/initializer of the parameter to the body
+ // - static field in a class expression
+ // - optional chaining pre-es2020
+ // - nullish coalesce pre-es2020
+ // - spread assignment in binding pattern pre-es2017
+ target := getEmitScriptTarget(r.compilerOptions)
+ if target >= ScriptTargetES2015 {
+ functionLocation := location
+ declarationRequiresScopeChange := r.getRequiresScopeChangeCache(functionLocation)
+ if declarationRequiresScopeChange == TSUnknown {
+ declarationRequiresScopeChange = boolToTristate(some(functionLocation.FunctionLikeData().parameters, r.requiresScopeChange))
+ r.setRequiresScopeChangeCache(functionLocation, declarationRequiresScopeChange)
+ }
+ return declarationRequiresScopeChange == TSTrue
+ }
+ }
+ }
+ return false
+}
+
+func (r *NameResolver) requiresScopeChange(node *Node) bool {
+ d := node.AsParameterDeclaration()
+ return r.requiresScopeChangeWorker(d.name) || d.initializer != nil && r.requiresScopeChangeWorker(d.initializer)
+}
+
+func (r *NameResolver) requiresScopeChangeWorker(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindArrowFunction, SyntaxKindFunctionExpression, SyntaxKindFunctionDeclaration, SyntaxKindConstructor:
+ return false
+ case SyntaxKindMethodDeclaration, SyntaxKindGetAccessor, SyntaxKindSetAccessor, SyntaxKindPropertyAssignment:
+ return r.requiresScopeChangeWorker(node.Name())
+ case SyntaxKindPropertyDeclaration:
+ if hasStaticModifier(node) {
+ return !getEmitStandardClassFields(r.compilerOptions)
+ }
+ return r.requiresScopeChangeWorker(node.AsPropertyDeclaration().name)
+ default:
+ if isNullishCoalesce(node) || isOptionalChain(node) {
+ return getEmitScriptTarget(r.compilerOptions) < ScriptTargetES2020
+ }
+ if isBindingElement(node) && node.AsBindingElement().dotDotDotToken != nil && isObjectBindingPattern(node.parent) {
+ return getEmitScriptTarget(r.compilerOptions) < ScriptTargetES2017
+ }
+ if isTypeNode(node) {
+ return false
+ }
+ return node.ForEachChild(r.requiresScopeChangeWorker)
+ }
+}
+
+func getIsDeferredContext(location *Node, lastLocation *Node) bool {
+ if location.kind != SyntaxKindArrowFunction && location.kind != SyntaxKindFunctionExpression {
+ // initializers in instance property declaration of class like entities are executed in constructor and thus deferred
+ // A name is evaluated within the enclosing scope - so it shouldn't count as deferred
+ return isTypeQueryNode(location) ||
+ (isFunctionLikeDeclaration(location) || location.kind == SyntaxKindPropertyDeclaration && !isStatic(location)) &&
+ (lastLocation == nil || lastLocation != location.Name())
+ }
+ if lastLocation != nil && lastLocation == location.Name() {
+ return false
+ }
+ // generator functions and async functions are not inlined in control flow when immediately invoked
+ if location.BodyData().asteriskToken != nil || hasSyntacticModifier(location, ModifierFlagsAsync) {
+ return true
+ }
+ return getImmediatelyInvokedFunctionExpression(location) == nil
+}
+
+func isTypeParameterSymbolDeclaredInContainer(symbol *Symbol, container *Node) bool {
+ for _, decl := range symbol.declarations {
+ if decl.kind == SyntaxKindTypeParameter {
+ parent := decl.parent.parent
+ if parent == container {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+func isSelfReferenceLocation(node *Node, lastLocation *Node) bool {
+ switch node.kind {
+ case SyntaxKindParameter:
+ return lastLocation != nil && lastLocation == node.AsParameterDeclaration().name
+ case SyntaxKindFunctionDeclaration, SyntaxKindClassDeclaration, SyntaxKindInterfaceDeclaration, SyntaxKindEnumDeclaration,
+ SyntaxKindTypeAliasDeclaration, SyntaxKindModuleDeclaration: // For `namespace N { N; }`
+ return true
+ }
+ return false
+}
+
+func isTypeReferenceIdentifier(node *Node) bool {
+ for node.parent.kind == SyntaxKindQualifiedName {
+ node = node.parent
+ }
+ return isTypeReferenceNode(node.parent)
+}
+
+func isInTypeQuery(node *Node) bool {
+ // TypeScript 1.0 spec (April 2014): 3.6.3
+ // A type query consists of the keyword typeof followed by an expression.
+ // The expression is restricted to a single identifier or a sequence of identifiers separated by periods
+ return findAncestorOrQuit(node, func(n *Node) FindAncestorResult {
+ switch n.kind {
+ case SyntaxKindTypeQuery:
+ return FindAncestorTrue
+ case SyntaxKindIdentifier, SyntaxKindQualifiedName:
+ return FindAncestorFalse
+ }
+ return FindAncestorQuit
+ }) != nil
+}
+
+func nodeKindIs(node *Node, kinds ...SyntaxKind) bool {
+ return slices.Contains(kinds, node.kind)
+}
+
+func isTypeOnlyImportDeclaration(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindImportSpecifier:
+ return node.AsImportSpecifier().isTypeOnly || node.parent.parent.AsImportClause().isTypeOnly
+ case SyntaxKindNamespaceImport:
+ return node.parent.AsImportClause().isTypeOnly
+ case SyntaxKindImportClause:
+ return node.AsImportClause().isTypeOnly
+ case SyntaxKindImportEqualsDeclaration:
+ return node.AsImportEqualsDeclaration().isTypeOnly
+ }
+ return false
+}
+
+func isTypeOnlyExportDeclaration(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindExportSpecifier:
+ return node.AsExportSpecifier().isTypeOnly || node.parent.parent.AsExportDeclaration().isTypeOnly
+ case SyntaxKindExportDeclaration:
+ d := node.AsExportDeclaration()
+ return d.isTypeOnly && d.moduleSpecifier != nil && d.exportClause == nil
+ case SyntaxKindNamespaceExport:
+ return node.parent.AsExportDeclaration().isTypeOnly
+ }
+ return false
+}
+
+func isTypeOnlyImportOrExportDeclaration(node *Node) bool {
+ return isTypeOnlyImportDeclaration(node) || isTypeOnlyExportDeclaration(node)
+}
+
+func getNameFromImportDeclaration(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindImportSpecifier:
+ return node.AsImportSpecifier().name
+ case SyntaxKindNamespaceImport:
+ return node.AsNamespaceImport().name
+ case SyntaxKindImportClause:
+ return node.AsImportClause().name
+ case SyntaxKindImportEqualsDeclaration:
+ return node.AsImportEqualsDeclaration().name
+ }
+ return nil
+}
+
+func isValidTypeOnlyAliasUseSite(useSite *Node) bool {
+ return useSite.flags&NodeFlagsAmbient != 0 ||
+ isPartOfTypeQuery(useSite) ||
+ isIdentifierInNonEmittingHeritageClause(useSite) ||
+ isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(useSite) ||
+ !(isExpressionNode(useSite) || isShorthandPropertyNameUseSite(useSite))
+}
+
+func isIdentifierInNonEmittingHeritageClause(node *Node) bool {
+ if node.kind != SyntaxKindIdentifier {
+ return false
+ }
+ heritageClause := findAncestorOrQuit(node.parent, func(parent *Node) FindAncestorResult {
+ switch parent.kind {
+ case SyntaxKindHeritageClause:
+ return FindAncestorTrue
+ case SyntaxKindPropertyAccessExpression, SyntaxKindExpressionWithTypeArguments:
+ return FindAncestorFalse
+ default:
+ return FindAncestorQuit
+ }
+ })
+ if heritageClause != nil {
+ return heritageClause.AsHeritageClause().token == SyntaxKindImmediateKeyword || heritageClause.parent.kind == SyntaxKindInterfaceDeclaration
+ }
+ return false
+}
+
+func isPartOfPossiblyValidTypeOrAbstractComputedPropertyName(node *Node) bool {
+ for nodeKindIs(node, SyntaxKindIdentifier, SyntaxKindPropertyAccessExpression) {
+ node = node.parent
+ }
+ if node.kind != SyntaxKindComputedPropertyName {
+ return false
+ }
+ if hasSyntacticModifier(node.parent, ModifierFlagsAbstract) {
+ return true
+ }
+ return nodeKindIs(node.parent.parent, SyntaxKindInterfaceDeclaration, SyntaxKindTypeLiteral)
+}
+
+func isExpressionNode(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindSuperKeyword, SyntaxKindNullKeyword, SyntaxKindTrueKeyword, SyntaxKindFalseKeyword, SyntaxKindRegularExpressionLiteral,
+ SyntaxKindArrayLiteralExpression, SyntaxKindObjectLiteralExpression, SyntaxKindPropertyAccessExpression, SyntaxKindElementAccessExpression,
+ SyntaxKindCallExpression, SyntaxKindNewExpression, SyntaxKindTaggedTemplateExpression, SyntaxKindAsExpression, SyntaxKindTypeAssertionExpression,
+ SyntaxKindSatisfiesExpression, SyntaxKindNonNullExpression, SyntaxKindParenthesizedExpression, SyntaxKindFunctionExpression,
+ SyntaxKindClassExpression, SyntaxKindArrowFunction, SyntaxKindVoidExpression, SyntaxKindDeleteExpression, SyntaxKindTypeOfExpression,
+ SyntaxKindPrefixUnaryExpression, SyntaxKindPostfixUnaryExpression, SyntaxKindBinaryExpression, SyntaxKindConditionalExpression,
+ SyntaxKindSpreadElement, SyntaxKindTemplateExpression, SyntaxKindOmittedExpression, SyntaxKindJsxElement, SyntaxKindJsxSelfClosingElement,
+ SyntaxKindJsxFragment, SyntaxKindYieldExpression, SyntaxKindAwaitExpression, SyntaxKindMetaProperty:
+ return true
+ case SyntaxKindExpressionWithTypeArguments:
+ return !isHeritageClause(node.parent)
+ case SyntaxKindQualifiedName:
+ for node.parent.kind == SyntaxKindQualifiedName {
+ node = node.parent
+ }
+ return isTypeQueryNode(node.parent) || isJSDocLinkLike(node.parent) || isJSXTagName(node)
+ case SyntaxKindJSDocMemberName:
+ return isTypeQueryNode(node.parent) || isJSDocLinkLike(node.parent) || isJSXTagName(node)
+ case SyntaxKindPrivateIdentifier:
+ return isBinaryExpression(node.parent) && node.parent.AsBinaryExpression().left == node && node.parent.AsBinaryExpression().operatorToken.kind == SyntaxKindInKeyword
+ case SyntaxKindIdentifier:
+ if isTypeQueryNode(node.parent) || isJSDocLinkLike(node.parent) || isJSXTagName(node) {
+ return true
+ }
+ fallthrough
+ case SyntaxKindNumericLiteral, SyntaxKindBigintLiteral, SyntaxKindStringLiteral, SyntaxKindNoSubstitutionTemplateLiteral, SyntaxKindThisKeyword:
+ return isInExpressionContext(node)
+ default:
+ return false
+ }
+}
+
+func isInExpressionContext(node *Node) bool {
+ parent := node.parent
+ switch parent.kind {
+ case SyntaxKindVariableDeclaration:
+ return parent.AsVariableDeclaration().initializer == node
+ case SyntaxKindParameter:
+ return parent.AsParameterDeclaration().initializer == node
+ case SyntaxKindPropertyDeclaration:
+ return parent.AsPropertyDeclaration().initializer == node
+ case SyntaxKindPropertySignature:
+ return parent.AsPropertySignatureDeclaration().initializer == node
+ case SyntaxKindEnumMember:
+ return parent.AsEnumMember().initializer == node
+ case SyntaxKindPropertyAssignment:
+ return parent.AsPropertyAssignment().initializer == node
+ case SyntaxKindBindingElement:
+ return parent.AsBindingElement().initializer == node
+ case SyntaxKindExpressionStatement:
+ return parent.AsExpressionStatement().expression == node
+ case SyntaxKindIfStatement:
+ return parent.AsIfStatement().expression == node
+ case SyntaxKindDoStatement:
+ return parent.AsDoStatement().expression == node
+ case SyntaxKindWhileStatement:
+ return parent.AsWhileStatement().expression == node
+ case SyntaxKindReturnStatement:
+ return parent.AsReturnStatement().expression == node
+ case SyntaxKindWithStatement:
+ return parent.AsWithStatement().expression == node
+ case SyntaxKindSwitchStatement:
+ return parent.AsSwitchStatement().expression == node
+ case SyntaxKindCaseClause, SyntaxKindDefaultClause:
+ return parent.AsCaseOrDefaultClause().expression == node
+ case SyntaxKindThrowStatement:
+ return parent.AsThrowStatement().expression == node
+ case SyntaxKindForStatement:
+ s := parent.AsForStatement()
+ return s.initializer == node && s.initializer.kind != SyntaxKindVariableDeclarationList || s.condition == node || s.incrementor == node
+ case SyntaxKindForInStatement, SyntaxKindForOfStatement:
+ s := parent.AsForInOrOfStatement()
+ return s.initializer == node && s.initializer.kind != SyntaxKindVariableDeclarationList || s.expression == node
+ case SyntaxKindTypeAssertionExpression:
+ return parent.AsTypeAssertion().expression == node
+ case SyntaxKindAsExpression:
+ return parent.AsAsExpression().expression == node
+ case SyntaxKindTemplateSpan:
+ return parent.AsTemplateSpan().expression == node
+ case SyntaxKindComputedPropertyName:
+ return parent.AsComputedPropertyName().expression == node
+ case SyntaxKindDecorator, SyntaxKindJsxExpression, SyntaxKindJsxSpreadAttribute, SyntaxKindSpreadAssignment:
+ return true
+ case SyntaxKindExpressionWithTypeArguments:
+ return parent.AsExpressionWithTypeArguments().expression == node && !isPartOfTypeNode(parent)
+ case SyntaxKindShorthandPropertyAssignment:
+ return parent.AsShorthandPropertyAssignment().objectAssignmentInitializer == node
+ case SyntaxKindSatisfiesExpression:
+ return parent.AsSatisfiesExpression().expression == node
+ default:
+ return isExpressionNode(parent)
+ }
+}
+
+func isPartOfTypeNode(node *Node) bool {
+ kind := node.kind
+ if kind >= SyntaxKindFirstTypeNode && kind <= SyntaxKindLastTypeNode {
+ return true
+ }
+ switch node.kind {
+ case SyntaxKindAnyKeyword, SyntaxKindUnknownKeyword, SyntaxKindNumberKeyword, SyntaxKindBigIntKeyword, SyntaxKindStringKeyword,
+ SyntaxKindBooleanKeyword, SyntaxKindSymbolKeyword, SyntaxKindObjectKeyword, SyntaxKindUndefinedKeyword, SyntaxKindNullKeyword,
+ SyntaxKindNeverKeyword:
+ return true
+ case SyntaxKindExpressionWithTypeArguments:
+ return isPartOfTypeExpressionWithTypeArguments(node)
+ case SyntaxKindTypeParameter:
+ return node.parent.kind == SyntaxKindMappedType || node.parent.kind == SyntaxKindInferType
+ case SyntaxKindIdentifier:
+ 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 SyntaxKindQualifiedName, SyntaxKindPropertyAccessExpression, SyntaxKindThisKeyword:
+ return isPartOfTypeNodeInParent(node)
+ }
+ return false
+}
+
+func isPartOfTypeNodeInParent(node *Node) bool {
+ parent := node.parent
+ // 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 >= SyntaxKindFirstTypeNode && parent.kind <= SyntaxKindLastTypeNode {
+ return true
+ }
+ switch parent.kind {
+ case SyntaxKindTypeQuery:
+ return false
+ case SyntaxKindImportType:
+ return !parent.AsImportTypeNode().isTypeOf
+ case SyntaxKindExpressionWithTypeArguments:
+ return isPartOfTypeExpressionWithTypeArguments(parent)
+ case SyntaxKindTypeParameter:
+ return node == parent.AsTypeParameter().constraint
+ case SyntaxKindPropertyDeclaration:
+ return node == parent.AsPropertyDeclaration().typeNode
+ case SyntaxKindPropertySignature:
+ return node == parent.AsPropertySignatureDeclaration().typeNode
+ case SyntaxKindParameter:
+ return node == parent.AsParameterDeclaration().typeNode
+ case SyntaxKindVariableDeclaration:
+ return node == parent.AsVariableDeclaration().typeNode
+ case SyntaxKindFunctionDeclaration, SyntaxKindFunctionExpression, SyntaxKindArrowFunction, SyntaxKindConstructor, SyntaxKindMethodDeclaration,
+ SyntaxKindMethodSignature, SyntaxKindGetAccessor, SyntaxKindSetAccessor, SyntaxKindCallSignature, SyntaxKindConstructSignature,
+ SyntaxKindIndexSignature:
+ return node == parent.FunctionLikeData().returnType
+ case SyntaxKindTypeAssertionExpression:
+ return node == parent.AsTypeAssertion().typeNode
+ case SyntaxKindCallExpression:
+ return typeArgumentListContains(parent.AsCallExpression().typeArguments, node)
+ case SyntaxKindNewExpression:
+ return typeArgumentListContains(parent.AsNewExpression().typeArguments, node)
+ case SyntaxKindTaggedTemplateExpression:
+ return typeArgumentListContains(parent.AsTaggedTemplateExpression().typeArguments, node)
+ }
+ return false
+}
+
+func isPartOfTypeExpressionWithTypeArguments(node *Node) bool {
+ parent := node.parent
+ return isHeritageClause(parent) && (!isClassLike(parent.parent) || parent.AsHeritageClause().token == SyntaxKindImplementsKeyword)
+}
+
+func typeArgumentListContains(list *Node, node *Node) bool {
+ if list != nil {
+ return slices.Contains(list.AsTypeArgumentList().arguments, node)
+ }
+ return false
+}
+
+func isJSDocLinkLike(node *Node) bool {
+ return nodeKindIs(node, SyntaxKindJSDocLink, SyntaxKindJSDocLinkCode, SyntaxKindJSDocLinkPlain)
+}
+
+func isJSXTagName(node *Node) bool {
+ parent := node.parent
+ switch parent.kind {
+ case SyntaxKindJsxOpeningElement:
+ return parent.AsJsxOpeningElement().tagName == node
+ case SyntaxKindJsxSelfClosingElement:
+ return parent.AsJsxSelfClosingElement().tagName == node
+ case SyntaxKindJsxClosingElement:
+ return parent.AsJsxClosingElement().tagName == node
+ }
+ return false
+}
+
+func isShorthandPropertyNameUseSite(useSite *Node) bool {
+ return isIdentifier(useSite) && isShorthandPropertyAssignment(useSite.parent) && useSite.parent.AsShorthandPropertyAssignment().name == useSite
+}
+
+func isTypeDeclaration(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindTypeParameter, SyntaxKindClassDeclaration, SyntaxKindInterfaceDeclaration, SyntaxKindTypeAliasDeclaration, SyntaxKindEnumDeclaration:
+ return true
+ case SyntaxKindImportClause:
+ return node.AsImportClause().isTypeOnly
+ case SyntaxKindImportSpecifier:
+ return node.parent.parent.AsImportClause().isTypeOnly
+ case SyntaxKindExportSpecifier:
+ return node.parent.parent.AsExportDeclaration().isTypeOnly
+ default:
+ return false
+ }
+}
+
+func canHaveSymbol(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindArrowFunction, SyntaxKindBinaryExpression, SyntaxKindBindingElement, SyntaxKindCallExpression, SyntaxKindCallSignature,
+ SyntaxKindClassDeclaration, SyntaxKindClassExpression, SyntaxKindClassStaticBlockDeclaration, SyntaxKindConstructor, SyntaxKindConstructorType,
+ SyntaxKindConstructSignature, SyntaxKindElementAccessExpression, SyntaxKindEnumDeclaration, SyntaxKindEnumMember, SyntaxKindExportAssignment,
+ SyntaxKindExportDeclaration, SyntaxKindExportSpecifier, SyntaxKindFunctionDeclaration, SyntaxKindFunctionExpression, SyntaxKindFunctionType,
+ SyntaxKindGetAccessor, SyntaxKindIdentifier, SyntaxKindImportClause, SyntaxKindImportEqualsDeclaration, SyntaxKindImportSpecifier,
+ SyntaxKindIndexSignature, SyntaxKindInterfaceDeclaration, SyntaxKindJSDocCallbackTag, SyntaxKindJSDocEnumTag, SyntaxKindJSDocFunctionType,
+ SyntaxKindJSDocParameterTag, SyntaxKindJSDocPropertyTag, SyntaxKindJSDocSignature, SyntaxKindJSDocTypedefTag, SyntaxKindJSDocTypeLiteral,
+ SyntaxKindJsxAttribute, SyntaxKindJsxAttributes, SyntaxKindJsxSpreadAttribute, SyntaxKindMappedType, SyntaxKindMethodDeclaration,
+ SyntaxKindMethodSignature, SyntaxKindModuleDeclaration, SyntaxKindNamedTupleMember, SyntaxKindNamespaceExport, SyntaxKindNamespaceExportDeclaration,
+ SyntaxKindNamespaceImport, SyntaxKindNewExpression, SyntaxKindNoSubstitutionTemplateLiteral, SyntaxKindNumericLiteral, SyntaxKindObjectLiteralExpression,
+ SyntaxKindParameter, SyntaxKindPropertyAccessExpression, SyntaxKindPropertyAssignment, SyntaxKindPropertyDeclaration, SyntaxKindPropertySignature,
+ SyntaxKindSetAccessor, SyntaxKindShorthandPropertyAssignment, SyntaxKindSourceFile, SyntaxKindSpreadAssignment, SyntaxKindStringLiteral,
+ SyntaxKindTypeAliasDeclaration, SyntaxKindTypeLiteral, SyntaxKindTypeParameter, SyntaxKindVariableDeclaration:
+ return true
+ }
+ return false
+}
+
+func canHaveLocals(node *Node) bool {
+ switch node.kind {
+ case SyntaxKindArrowFunction, SyntaxKindBlock, SyntaxKindCallSignature, SyntaxKindCaseBlock, SyntaxKindCatchClause,
+ SyntaxKindClassStaticBlockDeclaration, SyntaxKindConditionalType, SyntaxKindConstructor, SyntaxKindConstructorType,
+ SyntaxKindConstructSignature, SyntaxKindForStatement, SyntaxKindForInStatement, SyntaxKindForOfStatement, SyntaxKindFunctionDeclaration,
+ SyntaxKindFunctionExpression, SyntaxKindFunctionType, SyntaxKindGetAccessor, SyntaxKindIndexSignature, SyntaxKindJSDocCallbackTag,
+ SyntaxKindJSDocEnumTag, SyntaxKindJSDocFunctionType, SyntaxKindJSDocSignature, SyntaxKindJSDocTypedefTag, SyntaxKindMappedType,
+ SyntaxKindMethodDeclaration, SyntaxKindMethodSignature, SyntaxKindModuleDeclaration, SyntaxKindSetAccessor, SyntaxKindSourceFile,
+ SyntaxKindTypeAliasDeclaration:
+ return true
+ }
+ return false
+}
+
+func isAnyImportOrReExport(node *Node) bool {
+ return isAnyImportSyntax(node) || isExportDeclaration(node)
+}
+
+func isAnyImportSyntax(node *Node) bool {
+ return nodeKindIs(node, SyntaxKindImportDeclaration, SyntaxKindImportEqualsDeclaration)
+}
+
+func getExternalModuleName(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindImportDeclaration:
+ return node.AsImportDeclaration().moduleSpecifier
+ case SyntaxKindExportDeclaration:
+ return node.AsExportDeclaration().moduleSpecifier
+ case SyntaxKindImportEqualsDeclaration:
+ if node.AsImportEqualsDeclaration().moduleReference.kind == SyntaxKindExternalModuleReference {
+ return node.AsImportEqualsDeclaration().moduleReference.AsExternalModuleReference().expression
+ }
+ return nil
+ case SyntaxKindImportType:
+ return getImportTypeNodeLiteral(node)
+ case SyntaxKindCallExpression:
+ return node.AsCallExpression().arguments[0]
+ case SyntaxKindModuleDeclaration:
+ if isStringLiteral(node.AsModuleDeclaration().name) {
+ return node.AsModuleDeclaration().name
+ }
+ return nil
+ }
+ panic("Unhandled case in getExternalModuleName")
+}
+
+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 isExternalModuleNameRelative(moduleName string) bool {
+ // TypeScript 1.0 spec (April 2014): 11.2.1
+ // An external module name is "relative" if the first term is "." or "..".
+ // Update: We also consider a path like `C:\foo.ts` "relative" because we do not search for it in `node_modules` or treat it as an ambient module.
+ return pathIsRelative(moduleName) || isRootedDiskPath(moduleName)
+}
+
+func pathIsRelative(path string) bool {
+ return makeRegexp(`^\.\.?(?:$|[\\/])`).MatchString(path)
+}
+
+func isRootedDiskPath(path string) bool {
+ return false // !!!
+}
+
+func isShorthandAmbientModuleSymbol(moduleSymbol *Symbol) bool {
+ return isShorthandAmbientModule(moduleSymbol.valueDeclaration)
+}
+
+func isShorthandAmbientModule(node *Node) bool {
+ // The only kind of module that can be missing a body is a shorthand ambient module.
+ return node != nil && node.kind == SyntaxKindModuleDeclaration && node.AsModuleDeclaration().body == nil
+}
+
+func isEntityName(node *Node) bool {
+ return node.kind == SyntaxKindIdentifier || node.kind == SyntaxKindQualifiedName
+}
+
+func nodeIsSynthesized(node *Node) bool {
+ return node.loc.pos < 0 || node.loc.end < 0
+}
+
+func getFirstIdentifier(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindIdentifier:
+ return node
+ case SyntaxKindQualifiedName:
+ return getFirstIdentifier(node.AsQualifiedName().left)
+ case SyntaxKindPropertyAccessExpression:
+ return getFirstIdentifier(node.AsPropertyAccessExpression().expression)
+ }
+ panic("Unhandled case in getFirstIdentifier")
+}
+
+func getAliasDeclarationFromName(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindImportClause, SyntaxKindImportSpecifier, SyntaxKindNamespaceImport, SyntaxKindExportSpecifier, SyntaxKindExportAssignment,
+ SyntaxKindImportEqualsDeclaration, SyntaxKindNamespaceExport:
+ return node.parent
+ case SyntaxKindQualifiedName:
+ return getAliasDeclarationFromName(node.parent)
+ }
+ return nil
+}
+
+func entityNameToString(name *Node) string {
+ switch name.kind {
+ case SyntaxKindThisKeyword:
+ return "this"
+ case SyntaxKindIdentifier, SyntaxKindPrivateIdentifier:
+ return getTextOfNode(name)
+ case SyntaxKindQualifiedName:
+ return entityNameToString(name.AsQualifiedName().left) + "." + entityNameToString(name.AsQualifiedName().right)
+ case SyntaxKindPropertyAccessExpression:
+ return entityNameToString(name.AsPropertyAccessExpression().expression) + "." + entityNameToString(name.AsPropertyAccessExpression().name)
+ case SyntaxKindJsxNamespacedName:
+ return entityNameToString(name.AsJsxNamespacedName().namespace) + ":" + entityNameToString(name.AsJsxNamespacedName().name)
+ }
+ panic("Unhandled case in entityNameToString")
+}
+
+func getContainingQualifiedNameNode(node *Node) *Node {
+ for isQualifiedName(node.parent) {
+ node = node.parent
+ }
+ return node
+}
+
+var extensionsToRemove = []string{ExtensionDts, ExtensionDmts, ExtensionDcts, ExtensionMjs, ExtensionMts, ExtensionCjs, ExtensionCts, ExtensionTs, ExtensionJs, ExtensionTsx, ExtensionJsx, ExtensionJson}
+
+func removeFileExtension(path string) string {
+ // Remove any known extension even if it has more than one dot
+ for _, ext := range extensionsToRemove {
+ if strings.HasSuffix(path, ext) {
+ return path[:len(path)-len(ext)]
+ }
+ }
+ // Otherwise just remove single dot extension, if any
+ return path[:len(path)-len(filepath.Ext(path))]
+}
+
+func isSideEffectImport(node *Node) bool {
+ ancestor := findAncestor(node, isImportDeclaration)
+ return ancestor != nil && ancestor.AsImportDeclaration().importClause == nil
+}
+
+func getExternalModuleRequireArgument(node *Node) *Node {
+ if isVariableDeclarationInitializedToBareOrAccessedRequire(node) {
+ return getLeftmostAccessExpression(node.AsVariableDeclaration().initializer).AsCallExpression().arguments[0]
+ }
+ return nil
+}
+
+func getExternalModuleImportEqualsDeclarationExpression(node *Node) *Node {
+ //Debug.assert(isExternalModuleImportEqualsDeclaration(node))
+ return node.AsImportEqualsDeclaration().moduleReference.AsExternalModuleReference().expression
+}
+
+func isRightSideOfQualifiedNameOrPropertyAccess(node *Node) bool {
+ parent := node.parent
+ switch parent.kind {
+ case SyntaxKindQualifiedName:
+ return parent.AsQualifiedName().right == node
+ case SyntaxKindPropertyAccessExpression:
+ return parent.AsPropertyAccessExpression().name == node
+ case SyntaxKindMetaProperty:
+ return parent.AsMetaProperty().name == node
+ }
+ return false
+}
+
+func getNamespaceDeclarationNode(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindImportDeclaration:
+ importClause := node.AsImportDeclaration().importClause
+ if importClause != nil && isNamespaceImport(importClause.AsImportClause().namedBindings) {
+ return importClause.AsImportClause().namedBindings
+ }
+ case SyntaxKindImportEqualsDeclaration:
+ return node
+ case SyntaxKindExportDeclaration:
+ exportClause := node.AsExportDeclaration().exportClause
+ if exportClause != nil && isNamespaceExport(exportClause) {
+ return exportClause
+ }
+ default:
+ panic("Unhandled case in getNamespaceDeclarationNode")
+ }
+ return nil
+}
+
+func isImportCall(node *Node) bool {
+ return isCallExpression(node) && node.AsCallExpression().expression.kind == SyntaxKindImportKeyword
+}
+
+func getSourceFileOfModule(module *Symbol) *SourceFile {
+ declaration := module.valueDeclaration
+ if declaration == nil {
+ declaration = getNonAugmentationDeclaration(module)
+ }
+ return getSourceFileOfNode(declaration)
+}
+
+func getNonAugmentationDeclaration(symbol *Symbol) *Node {
+ return find(symbol.declarations, func(d *Node) bool {
+ return !isExternalModuleAugmentation(d) && !(isModuleDeclaration(d) && isGlobalScopeAugmentation(d))
+ })
+}
+
+func isExternalModuleAugmentation(node *Node) bool {
+ return isAmbientModule(node) && isModuleAugmentationExternal(node)
+}
+
+func isJsonSourceFile(file *SourceFile) bool {
+ return file.scriptKind == ScriptKindJSON
+}
+
+func isSyntacticDefault(node *Node) bool {
+ return (isExportAssignment(node) && !node.AsExportAssignment().isExportEquals) ||
+ hasSyntacticModifier(node, ModifierFlagsDefault) ||
+ isExportSpecifier(node) ||
+ isNamespaceExport(node)
+}
+
+func hasExportAssignmentSymbol(moduleSymbol *Symbol) bool {
+ return moduleSymbol.exports[InternalSymbolNameExportEquals] != nil
+}
+
+func isImportOrExportSpecifier(node *Node) bool {
+ return isImportSpecifier(node) || isExportSpecifier(node)
+}
+
+func parsePseudoBigint(stringValue string) string {
+ return stringValue // !!!
+}
+
+func isTypeAlias(node *Node) bool {
+ return isTypeAliasDeclaration(node)
+}
+
+/**
+ * Gets the effective type parameters. If the node was parsed in a
+ * JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
+ *
+ * This does *not* return type parameters from a jsdoc reference to a generic type, eg
+ *
+ * type Id = (x: T) => T
+ * /** @type {Id} /
+ * function id(x) { return x }
+ */
+
+func getEffectiveTypeParameterDeclarations(node *Node) []*Node {
+ // if isJSDocSignature(node) {
+ // if isJSDocOverloadTag(node.parent) {
+ // jsDoc := getJSDocRoot(node.parent)
+ // if jsDoc && length(jsDoc.tags) {
+ // return flatMap(jsDoc.tags, func(tag JSDocTag) *NodeArray[TypeParameterDeclaration] {
+ // if isJSDocTemplateTag(tag) {
+ // return tag.typeParameters
+ // } else {
+ // return nil
+ // }
+ // })
+ // }
+ // }
+ // return emptyArray
+ // }
+ // if isJSDocTypeAlias(node) {
+ // Debug.assert(node.parent.kind == SyntaxKindJSDoc)
+ // return flatMap(node.parent.tags, func(tag JSDocTag) *NodeArray[TypeParameterDeclaration] {
+ // if isJSDocTemplateTag(tag) {
+ // return tag.typeParameters
+ // } else {
+ // return nil
+ // }
+ // })
+ // }
+ typeParameters := getTypeParameterListFromNode(node)
+ if typeParameters != nil {
+ return typeParameters.AsTypeParameterList().parameters
+ }
+ // if isInJSFile(node) {
+ // decls := getJSDocTypeParameterDeclarations(node)
+ // if decls.length {
+ // return decls
+ // }
+ // typeTag := getJSDocType(node)
+ // if typeTag && isFunctionTypeNode(typeTag) && typeTag.typeParameters {
+ // return typeTag.typeParameters
+ // }
+ // }
+ return nil
+}
+
+func getTypeParameterListFromNode(node *Node) *Node {
+ if isFunctionLike(node) {
+ return node.FunctionLikeData().typeParameters
+ }
+ switch node.kind {
+ case SyntaxKindClassDeclaration:
+ return node.AsClassDeclaration().typeParameters
+ case SyntaxKindClassExpression:
+ return node.AsClassExpression().typeParameters
+ case SyntaxKindInterfaceDeclaration:
+ return node.AsInterfaceDeclaration().typeParameters
+ case SyntaxKindTypeAliasDeclaration:
+ return node.AsTypeAliasDeclaration().typeParameters
+ }
+ panic("Unhandled case in getTypeParameterListFromNode")
+}
+
+func getInitializerFromNode(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindVariableDeclaration:
+ return node.AsVariableDeclaration().initializer
+ case SyntaxKindParameter:
+ return node.AsParameterDeclaration().initializer
+ case SyntaxKindBindingElement:
+ return node.AsBindingElement().initializer
+ case SyntaxKindPropertyDeclaration:
+ return node.AsPropertyDeclaration().initializer
+ case SyntaxKindPropertyAssignment:
+ return node.AsPropertyAssignment().initializer
+ case SyntaxKindEnumMember:
+ return node.AsEnumMember().initializer
+ case SyntaxKindForStatement:
+ return node.AsForStatement().initializer
+ case SyntaxKindForInStatement, SyntaxKindForOfStatement:
+ return node.AsForInOrOfStatement().initializer
+ case SyntaxKindJsxAttribute:
+ return node.AsJsxAttribute().initializer
+ }
+ return nil
+}
+
+/**
+ * Gets the effective type annotation of a variable, parameter, or property. If the node was
+ * parsed in a JavaScript file, gets the type annotation from JSDoc. Also gets the type of
+ * functions only the JSDoc case.
+ */
+func getEffectiveTypeAnnotationNode(node *Node) *Node {
+ if isTypeAliasDeclaration(node) {
+ return nil
+ }
+ switch node.kind {
+ case SyntaxKindVariableDeclaration:
+ return node.AsVariableDeclaration().typeNode
+ case SyntaxKindParameter:
+ return node.AsParameterDeclaration().typeNode
+ case SyntaxKindPropertySignature:
+ return node.AsPropertySignatureDeclaration().typeNode
+ case SyntaxKindPropertyDeclaration:
+ return node.AsPropertyDeclaration().typeNode
+ case SyntaxKindTypePredicate:
+ return node.AsTypePredicateNode().typeNode
+ case SyntaxKindParenthesizedType:
+ return node.AsParenthesizedTypeNode().typeNode
+ case SyntaxKindTypeOperator:
+ return node.AsTypeOperatorNode().typeNode
+ case SyntaxKindMappedType:
+ return node.AsMappedTypeNode().typeNode
+ case SyntaxKindTypeAssertionExpression:
+ return node.AsTypeAssertion().typeNode
+ case SyntaxKindAsExpression:
+ return node.AsAsExpression().typeNode
+ default:
+ if isFunctionLike(node) && !isFunctionDeclaration(node) {
+ return node.FunctionLikeData().returnType
+ }
+ }
+ return nil
+}
+
+func isTypeAny(t *Type) bool {
+ return t != nil && t.flags&TypeFlagsAny != 0
+}
+
+func isJSDocOptionalParameter(node *ParameterDeclaration) bool {
+ return false // !!!
+}
+
+func isQuestionToken(node *Node) bool {
+ return node != nil && node.kind == SyntaxKindQuestionToken
+}
+
+func isOptionalDeclaration(declaration *Node) bool {
+ switch declaration.kind {
+ case SyntaxKindPropertyDeclaration:
+ return isQuestionToken(declaration.AsPropertyDeclaration().postfixToken)
+ case SyntaxKindPropertySignature:
+ return isQuestionToken(declaration.AsPropertySignatureDeclaration().postfixToken)
+ case SyntaxKindParameter:
+ return declaration.AsParameterDeclaration().questionToken != nil
+ }
+ return false
+}
+
+func isEmptyArrayLiteral(expression *Node) bool {
+ return expression.kind == SyntaxKindArrayLiteralExpression && len(expression.AsArrayLiteralExpression().elements) == 0
+}
+
+func declarationBelongsToPrivateAmbientMember(declaration *Node) bool {
+ root := getRootDeclaration(declaration)
+ memberDeclaration := root
+ if root.kind == SyntaxKindParameter {
+ memberDeclaration = root.parent
+ }
+ return isPrivateWithinAmbient(memberDeclaration)
+}
+
+func isPrivateWithinAmbient(node *Node) bool {
+ return (hasEffectiveModifier(node, ModifierFlagsPrivate) || isPrivateIdentifierClassElementDeclaration(node)) && node.flags&NodeFlagsAmbient != 0
+}
+
+func identifierToKeywordKind(node *Identifier) SyntaxKind {
+ return textToKeyword[node.text]
+}
+
+func isAssertionExpression(node *Node) bool {
+ kind := node.kind
+ return kind == SyntaxKindTypeAssertionExpression || kind == SyntaxKindAsExpression
+}
+
+func createSymbolTable(symbols []*Symbol) SymbolTable {
+ if len(symbols) == 0 {
+ return nil
+ }
+ result := make(SymbolTable)
+ for _, symbol := range symbols {
+ result[symbol.name] = symbol
+ }
+ return result
+}
+
+func sortSymbols(symbols []*Symbol) {
+ slices.SortFunc(symbols, compareSymbols)
+}
+
+func compareSymbols(s1, s2 *Symbol) int {
+ if s1 == s2 {
+ return 0
+ }
+ if s1.valueDeclaration != nil && s2.valueDeclaration != nil {
+ if s1.parent != nil && s2.parent != nil {
+ // Symbols with the same unmerged parent are always in the same file
+ if s1.parent != s2.parent {
+ f1 := getSourceFileOfNode(s1.valueDeclaration)
+ f2 := getSourceFileOfNode(s2.valueDeclaration)
+ if f1 != f2 {
+ // In different files, first compare base filename
+ r := strings.Compare(filepath.Base(f1.path), filepath.Base(f2.path))
+ if r == 0 {
+ // Same base filename, compare the full paths (no two files should have the same full path)
+ r = strings.Compare(f1.path, f2.path)
+ }
+ return r
+ }
+ }
+ // In the same file, compare source positions
+ return s1.valueDeclaration.Pos() - s2.valueDeclaration.Pos()
+ }
+ }
+ // Sort by name
+ r := strings.Compare(s1.name, s2.name)
+ if r == 0 {
+ // Same name, sort by symbol id
+ r = int(getSymbolId(s1)) - int(getSymbolId(s2))
+ }
+ return r
+}
+
+func getClassLikeDeclarationOfSymbol(symbol *Symbol) *Node {
+ return find(symbol.declarations, isClassLike)
+}
+
+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 == SyntaxKindTypeQuery
+}
+
+func isThisIdentifier(node *Node) bool {
+ return node != nil && node.kind == SyntaxKindIdentifier && identifierIsThisKeyword(node)
+}
+
+func identifierIsThisKeyword(id *Node) bool {
+ return id.AsIdentifier().text == "this"
+}
+
+func getDeclarationModifierFlagsFromSymbol(s *Symbol, isWrite bool) ModifierFlags {
+ if s.valueDeclaration != nil {
+ var declaration *Node
+ if isWrite {
+ declaration = find(s.declarations, isSetAccessorDeclaration)
+ }
+ if declaration == nil && s.flags&SymbolFlagsGetAccessor != 0 {
+ declaration = find(s.declarations, isGetAccessorDeclaration)
+ }
+ if declaration == nil {
+ declaration = s.valueDeclaration
+ }
+ flags := getCombinedModifierFlags(declaration)
+ if s.parent != nil && s.parent.flags&SymbolFlagsClass != 0 {
+ return flags
+ }
+ return flags & ^ModifierFlagsAccessibilityModifier
+ }
+ if s.checkFlags&CheckFlagsSynthetic != 0 {
+ var accessModifier ModifierFlags
+ switch {
+ case s.checkFlags&CheckFlagsContainsPrivate != 0:
+ accessModifier = ModifierFlagsPrivate
+ case s.checkFlags&CheckFlagsContainsPublic != 0:
+ accessModifier = ModifierFlagsPublic
+ default:
+ accessModifier = ModifierFlagsProtected
+ }
+ var staticModifier ModifierFlags
+ if s.checkFlags&CheckFlagsContainsStatic != 0 {
+ staticModifier = ModifierFlagsStatic
+ }
+ return accessModifier | staticModifier
+ }
+ if s.flags&SymbolFlagsPrototype != 0 {
+ return ModifierFlagsPublic | ModifierFlagsStatic
+ }
+ return ModifierFlagsNone
+}
+
+func isExponentiationOperator(kind SyntaxKind) bool {
+ return kind == SyntaxKindAsteriskAsteriskToken
+}
+
+func isMultiplicativeOperator(kind SyntaxKind) bool {
+ return kind == SyntaxKindAsteriskToken || kind == SyntaxKindSlashToken || kind == SyntaxKindPercentToken
+}
+
+func isMultiplicativeOperatorOrHigher(kind SyntaxKind) bool {
+ return isExponentiationOperator(kind) || isMultiplicativeOperator(kind)
+}
+
+func isAdditiveOperator(kind SyntaxKind) bool {
+ return kind == SyntaxKindPlusToken || kind == SyntaxKindMinusToken
+}
+
+func isAdditiveOperatorOrHigher(kind SyntaxKind) bool {
+ return isAdditiveOperator(kind) || isMultiplicativeOperatorOrHigher(kind)
+}
+
+func isShiftOperator(kind SyntaxKind) bool {
+ return kind == SyntaxKindLessThanLessThanToken || kind == SyntaxKindGreaterThanGreaterThanToken ||
+ kind == SyntaxKindGreaterThanGreaterThanGreaterThanToken
+}
+
+func isShiftOperatorOrHigher(kind SyntaxKind) bool {
+ return isShiftOperator(kind) || isAdditiveOperatorOrHigher(kind)
+}
+
+func isRelationalOperator(kind SyntaxKind) bool {
+ return kind == SyntaxKindLessThanToken || kind == SyntaxKindLessThanEqualsToken || kind == SyntaxKindGreaterThanToken ||
+ kind == SyntaxKindGreaterThanEqualsToken || kind == SyntaxKindInstanceOfKeyword || kind == SyntaxKindInKeyword
+}
+
+func isRelationalOperatorOrHigher(kind SyntaxKind) bool {
+ return isRelationalOperator(kind) || isShiftOperatorOrHigher(kind)
+}
+
+func isEqualityOperator(kind SyntaxKind) bool {
+ return kind == SyntaxKindEqualsEqualsToken || kind == SyntaxKindEqualsEqualsEqualsToken ||
+ kind == SyntaxKindExclamationEqualsToken || kind == SyntaxKindExclamationEqualsEqualsToken
+}
+
+func isEqualityOperatorOrHigher(kind SyntaxKind) bool {
+ return isEqualityOperator(kind) || isRelationalOperatorOrHigher(kind)
+}
+
+func isBitwiseOperator(kind SyntaxKind) bool {
+ return kind == SyntaxKindAmpersandToken || kind == SyntaxKindBarToken || kind == SyntaxKindCaretToken
+}
+
+func isBitwiseOperatorOrHigher(kind SyntaxKind) bool {
+ return isBitwiseOperator(kind) || isEqualityOperatorOrHigher(kind)
+}
+
+// NOTE: The version in utilities includes ExclamationToken, which is not a binary operator.
+func isLogicalOperator(kind SyntaxKind) bool {
+ return kind == SyntaxKindAmpersandAmpersandToken || kind == SyntaxKindBarBarToken
+}
+
+func isLogicalOperatorOrHigher(kind SyntaxKind) bool {
+ return isLogicalOperator(kind) || isBitwiseOperatorOrHigher(kind)
+}
+
+func isAssignmentOperatorOrHigher(kind SyntaxKind) bool {
+ return kind == SyntaxKindQuestionQuestionToken || isLogicalOperatorOrHigher(kind) || isAssignmentOperator(kind)
+}
+
+func isBinaryOperator(kind SyntaxKind) bool {
+ return isAssignmentOperatorOrHigher(kind) || kind == SyntaxKindCommaToken
+}
+
+func isObjectLiteralType(t *Type) bool {
+ return t.objectFlags&ObjectFlagsObjectLiteral != 0
+}
+
+func isTupleType(t *Type) bool {
+ return t.objectFlags&ObjectFlagsReference != 0 && t.TypeReference().target.objectFlags&ObjectFlagsTuple != 0
+}
+
+func isDeclarationReadonly(declaration *Node) bool {
+ return getCombinedModifierFlags(declaration)&ModifierFlagsReadonly != 0 && !isParameterPropertyDeclaration(declaration, declaration.parent)
+}
+
+func isFreshLiteralType(t *Type) bool {
+ return t.flags&TypeFlagsFreshable != 0 && t.LiteralType().freshType == t
+}
+
+func getPostfixTokenFromNode(node *Node) *Node {
+ switch node.kind {
+ case SyntaxKindPropertyDeclaration:
+ return node.AsPropertyDeclaration().postfixToken
+ case SyntaxKindPropertySignature:
+ return node.AsPropertySignatureDeclaration().postfixToken
+ case SyntaxKindMethodDeclaration:
+ return node.AsMethodDeclaration().postfixToken
+ case SyntaxKindMethodSignature:
+ return node.AsMethodSignatureDeclaration().postfixToken
+ }
+ panic("Unhandled case in getPostfixTokenFromNode")
+}
+
+func isStatic(node *Node) bool {
+ // https://tc39.es/ecma262/#sec-static-semantics-isstatic
+ return isClassElement(node) && hasStaticModifier(node) || isClassStaticBlockDeclaration(node)
+}
+
+func isLogicalExpression(node *Node) bool {
+ for {
+ if node.kind == SyntaxKindParenthesizedExpression {
+ node = node.AsParenthesizedExpression().expression
+ } else if node.kind == SyntaxKindPrefixUnaryExpression && node.AsPrefixUnaryExpression().operator == SyntaxKindExclamationToken {
+ node = node.AsPrefixUnaryExpression().operand
+ } else {
+ return isLogicalOrCoalescingBinaryExpression(node)
+ }
+ }
+}