package parser import ( "strconv" "strings" "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/diagnostics" "github.com/microsoft/typescript-go/internal/scanner" ) func (p *Parser) finishReparsedNode(node *ast.Node, locationNode *ast.Node) { node.Flags = p.contextFlags | ast.NodeFlagsReparsed node.Loc = locationNode.Loc p.overrideParentInImmediateChildren(node) } func (p *Parser) finishMutatedNode(node *ast.Node) { p.overrideParentInImmediateChildren(node) } // Deep-clone the given node and add the clone to the reparsed clone list. The list is used by ast.GetReparsedNodeForNode // to locate reparsed clones of JSDoc nodes. Since the binder attaches symbols to reparsed nodes and not to JSDoc nodes, we // need the mapping when obtaining symbols and types from JSDoc nodes. func (p *Parser) addDeepCloneReparse(node *ast.Node) *ast.Node { clone := p.factory.DeepCloneReparse(node) if clone != nil { p.reparsedClones = append(p.reparsedClones, clone) } return clone } func (p *Parser) addTransformedReparse(newNode *ast.Node, old *ast.Node) *ast.Node { p.finishReparsedNode(newNode, old) newNode.Flags |= ast.NodeFlagsReparserTransformedLiteral p.reparsedClones = append(p.reparsedClones, newNode) return newNode } func (p *Parser) checkNonIdentifierName(name *ast.Node) *ast.Node { if ast.IsIdentifier(name) && !scanner.IsValidIdentifier(name.AsIdentifier().Text) { errLoc := name.Loc if errLoc.Len() == 0 { // missing name, emit error on the character before the missing name node errLoc = core.NewTextRange(name.Loc.Pos()-1, name.Loc.Pos()) } p.parseErrorAtRange(errLoc, diagnostics.Identifier_expected) } return name } // Hosted tags find a host and add their children to the correct location under the host. // Unhosted tags add synthetic nodes to the reparse list. func (p *Parser) reparseTags(parent *ast.Node, jsDoc []*ast.Node) { for _, j := range jsDoc { isLast := j == jsDoc[len(jsDoc)-1] tags := j.AsJSDoc().Tags if tags == nil { continue } for _, tag := range tags.Nodes { p.reparseUnhosted(tag, parent, j) if isLast { p.reparseHosted(tag, parent, j) } } } } func (p *Parser) reparseUnhosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Node) { switch tag.Kind { case ast.KindJSDocTypedefTag: typeExpression := tag.TypeExpression() if typeExpression == nil { break } fullName := tag.Name() isNamespace := fullName != nil && ast.IsModuleDeclaration(fullName) var modifiers *ast.ModifierList if isNamespace { modifiers = p.createExportModifier(tag) } typeAlias := p.factory.NewJSTypeAliasDeclaration(modifiers, p.addDeepCloneReparse(p.checkNonIdentifierName(p.getInnermostNameOfJSDocNamespace(fullName))), nil, nil) typeAlias.AsTypeAliasDeclaration().TypeParameters = p.gatherTypeParameters(jsDoc, true /*typedefOrCallback*/) var t *ast.Node switch typeExpression.Kind { case ast.KindJSDocTypeExpression: t = p.addDeepCloneReparse(typeExpression.Type()) case ast.KindJSDocTypeLiteral: t = p.reparseJSDocTypeLiteral(typeExpression) default: panic("typedef tag type expression should be a name reference or a type expression" + typeExpression.Kind.String()) } typeAlias.AsTypeAliasDeclaration().Type = t p.finishReparsedNode(typeAlias, tag) p.jsdocInfos = append(p.jsdocInfos, JSDocInfo{parent: typeAlias, jsDocs: []*ast.Node{jsDoc}}) typeAlias.Flags |= ast.NodeFlagsHasJSDoc result := p.wrapInJSDocNamespace(fullName, typeAlias, false /*nested*/) p.reparseList = append(p.reparseList, result) case ast.KindJSDocCallbackTag: typeExpression := tag.TypeExpression() if typeExpression == nil { break } fullName := tag.Name() isNamespace := fullName != nil && ast.IsModuleDeclaration(fullName) var modifiers *ast.ModifierList if isNamespace { modifiers = p.createExportModifier(tag) } functionType := p.reparseJSDocSignature(typeExpression, tag, jsDoc, tag, nil) typeAlias := p.factory.NewJSTypeAliasDeclaration(modifiers, p.addDeepCloneReparse(p.getInnermostNameOfJSDocNamespace(fullName)), nil, functionType) typeAlias.AsTypeAliasDeclaration().TypeParameters = p.gatherTypeParameters(jsDoc, true /*typedefOrCallback*/) p.finishReparsedNode(typeAlias, tag) p.jsdocInfos = append(p.jsdocInfos, JSDocInfo{parent: typeAlias, jsDocs: []*ast.Node{jsDoc}}) typeAlias.Flags |= ast.NodeFlagsHasJSDoc result := p.wrapInJSDocNamespace(fullName, typeAlias, false /*nested*/) p.reparseList = append(p.reparseList, result) case ast.KindJSDocImportTag: importTag := tag.AsJSDocImportTag() if importTag.ImportClause == nil { break } importClause := p.addDeepCloneReparse(importTag.ImportClause) importClause.AsImportClause().PhaseModifier = ast.KindTypeKeyword importDeclaration := p.factory.NewJSImportDeclaration( p.factory.DeepCloneReparseModifiers(importTag.Modifiers()), importClause, p.addDeepCloneReparse(importTag.ModuleSpecifier), p.addDeepCloneReparse(importTag.Attributes), ) p.finishReparsedNode(importDeclaration, tag) p.reparseList = append(p.reparseList, importDeclaration) case ast.KindJSDocOverloadTag: // Create overload signatures only for function, method, and constructor declarations outside object literals if (ast.IsFunctionDeclaration(parent) || ast.IsMethodDeclaration(parent) || ast.IsConstructorDeclaration(parent)) && p.parsingContexts&(1<