package parser import ( "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core" ) 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) } func (p *Parser) reparseCommonJS(node *ast.Node, jsdoc []*ast.Node) { if p.scriptKind != core.ScriptKindJS && p.scriptKind != core.ScriptKindJSX { return } if node.Kind != ast.KindExpressionStatement || node.AsExpressionStatement().Expression.Kind != ast.KindBinaryExpression { return } bin := node.AsExpressionStatement().Expression.AsBinaryExpression() kind := ast.GetAssignmentDeclarationKind(bin) var export *ast.Node switch kind { case ast.JSDeclarationKindModuleExports: export = p.factory.NewJSExportAssignment(nil, p.factory.DeepCloneReparse(bin.Right)) case ast.JSDeclarationKindExportsProperty: mod := p.factory.NewModifier(ast.KindExportKeyword) mod.Flags = p.contextFlags | ast.NodeFlagsReparsed mod.Loc = bin.Loc // TODO: Name can sometimes be a string literal, so downstream code needs to handle this export = p.factory.NewCommonJSExport( p.newModifierList(bin.Loc, p.nodeSlicePool.NewSlice1(mod)), p.factory.DeepCloneReparse(ast.GetElementOrPropertyAccessName(bin.Left)), nil, /*typeNode*/ p.factory.DeepCloneReparse(bin.Right)) } if export != nil { p.reparseList = append(p.reparseList, export) p.commonJSModuleIndicator = export p.reparseTags(export, jsdoc) p.finishReparsedNode(export, bin.AsNode()) } } // 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 { if parent.Kind != ast.KindCommonJSExport && parent.Kind != ast.KindJSExportAssignment { 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: // !!! Don't mark typedefs as exported if they are not in a module typeExpression := tag.AsJSDocTypedefTag().TypeExpression if typeExpression == nil { break } export := p.factory.NewModifier(ast.KindExportKeyword) export.Loc = tag.Loc export.Flags = p.contextFlags | ast.NodeFlagsReparsed modifiers := p.newModifierList(export.Loc, p.nodeSlicePool.NewSlice1(export)) typeAlias := p.factory.NewJSTypeAliasDeclaration(modifiers, p.factory.DeepCloneReparse(tag.AsJSDocTypedefTag().Name()), nil, nil) typeAlias.AsTypeAliasDeclaration().TypeParameters = p.gatherTypeParameters(jsDoc, tag) var t *ast.Node switch typeExpression.Kind { case ast.KindJSDocTypeExpression: t = p.factory.DeepCloneReparse(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.reparseList = append(p.reparseList, typeAlias) case ast.KindJSDocCallbackTag: callbackTag := tag.AsJSDocCallbackTag() if callbackTag.TypeExpression == nil { break } export := p.factory.NewModifier(ast.KindExportKeyword) export.Loc = tag.Loc export.Flags = p.contextFlags | ast.NodeFlagsReparsed modifiers := p.newModifierList(export.Loc, p.nodeSlicePool.NewSlice1(export)) functionType := p.reparseJSDocSignature(callbackTag.TypeExpression, tag, jsDoc, tag, nil) typeAlias := p.factory.NewJSTypeAliasDeclaration(modifiers, p.factory.DeepCloneReparse(callbackTag.FullName), nil, functionType) typeAlias.AsTypeAliasDeclaration().TypeParameters = p.gatherTypeParameters(jsDoc, tag) p.finishReparsedNode(typeAlias, tag) p.reparseList = append(p.reparseList, typeAlias) case ast.KindJSDocImportTag: importTag := tag.AsJSDocImportTag() if importTag.ImportClause == nil { break } importClause := p.factory.DeepCloneReparse(importTag.ImportClause) importClause.AsImportClause().PhaseModifier = ast.KindTypeKeyword importDeclaration := p.factory.NewJSImportDeclaration( p.factory.DeepCloneReparseModifiers(importTag.Modifiers()), importClause, p.factory.DeepCloneReparse(importTag.ModuleSpecifier), p.factory.DeepCloneReparse(importTag.Attributes), ) p.finishReparsedNode(importDeclaration, tag) p.reparseList = append(p.reparseList, importDeclaration) case ast.KindJSDocOverloadTag: if fun, ok := getFunctionLikeHost(parent); ok { p.reparseList = append(p.reparseList, p.reparseJSDocSignature(tag.AsJSDocOverloadTag().TypeExpression, fun, jsDoc, tag, fun.Modifiers())) } } } func (p *Parser) reparseJSDocSignature(jsSignature *ast.Node, fun *ast.Node, jsDoc *ast.Node, tag *ast.Node, modifiers *ast.ModifierList) *ast.Node { var signature *ast.Node clonedModifiers := p.factory.DeepCloneReparseModifiers(modifiers) switch fun.Kind { case ast.KindFunctionDeclaration, ast.KindFunctionExpression, ast.KindArrowFunction: signature = p.factory.NewFunctionDeclaration(clonedModifiers, nil, p.factory.DeepCloneReparse(fun.Name()), nil, nil, nil, nil, nil) case ast.KindMethodDeclaration, ast.KindMethodSignature: signature = p.factory.NewMethodDeclaration(clonedModifiers, nil, p.factory.DeepCloneReparse(fun.Name()), nil, nil, nil, nil, nil, nil) case ast.KindConstructor: signature = p.factory.NewConstructorDeclaration(clonedModifiers, nil, nil, nil, nil, nil) case ast.KindJSDocCallbackTag: signature = p.factory.NewFunctionTypeNode(nil, nil, nil) default: panic("Unexpected kind " + fun.Kind.String()) } if tag.Kind != ast.KindJSDocCallbackTag { signature.FunctionLikeData().TypeParameters = p.gatherTypeParameters(jsDoc, tag) } parameters := p.nodeSlicePool.NewSlice(0) for _, param := range jsSignature.Parameters() { var parameter *ast.Node if param.Kind == ast.KindJSDocThisTag { thisTag := param.AsJSDocThisTag() thisIdent := p.factory.NewIdentifier("this") thisIdent.Loc = thisTag.Loc thisIdent.Flags = p.contextFlags | ast.NodeFlagsReparsed parameter = p.factory.NewParameterDeclaration(nil, nil, thisIdent, nil, nil, nil) if thisTag.TypeExpression != nil { parameter.AsParameterDeclaration().Type = p.factory.DeepCloneReparse(thisTag.TypeExpression.Type()) } } else { jsparam := param.AsJSDocParameterOrPropertyTag() var dotDotDotToken *ast.Node var paramType *ast.TypeNode if jsparam.TypeExpression != nil { if jsparam.TypeExpression.Type().Kind == ast.KindJSDocVariadicType { dotDotDotToken = p.factory.NewToken(ast.KindDotDotDotToken) dotDotDotToken.Loc = jsparam.Loc dotDotDotToken.Flags = p.contextFlags | ast.NodeFlagsReparsed variadicType := jsparam.TypeExpression.Type().AsJSDocVariadicType() paramType = p.reparseJSDocTypeLiteral(variadicType.Type) } else { paramType = p.reparseJSDocTypeLiteral(jsparam.TypeExpression.Type()) } } parameter = p.factory.NewParameterDeclaration(nil, dotDotDotToken, p.factory.DeepCloneReparse(jsparam.Name()), p.makeQuestionIfOptional(jsparam), paramType, nil) } p.finishReparsedNode(parameter, param) parameters = append(parameters, parameter) } signature.FunctionLikeData().Parameters = p.newNodeList(jsSignature.AsJSDocSignature().Parameters.Loc, parameters) if jsSignature.Type() != nil && jsSignature.Type().AsJSDocReturnTag().TypeExpression != nil { signature.FunctionLikeData().Type = p.factory.DeepCloneReparse(jsSignature.Type().AsJSDocReturnTag().TypeExpression.Type()) } loc := jsSignature if tag.Kind == ast.KindJSDocOverloadTag { loc = tag.AsJSDocOverloadTag().TagName } p.finishReparsedNode(signature, loc) return signature } func (p *Parser) reparseJSDocTypeLiteral(t *ast.TypeNode) *ast.Node { if t == nil { return nil } if t.Kind == ast.KindJSDocTypeLiteral { jstypeliteral := t.AsJSDocTypeLiteral() isArrayType := jstypeliteral.IsArrayType properties := p.nodeSlicePool.NewSlice(0) for _, prop := range jstypeliteral.JSDocPropertyTags { jsprop := prop.AsJSDocParameterOrPropertyTag() name := prop.Name() if name.Kind == ast.KindQualifiedName { name = name.AsQualifiedName().Right } property := p.factory.NewPropertySignatureDeclaration(nil, p.factory.DeepCloneReparse(name), p.makeQuestionIfOptional(jsprop), nil, nil) if jsprop.TypeExpression != nil { property.AsPropertySignatureDeclaration().Type = p.reparseJSDocTypeLiteral(jsprop.TypeExpression.Type()) } p.finishReparsedNode(property, prop) properties = append(properties, property) } t = p.factory.NewTypeLiteralNode(p.newNodeList(jstypeliteral.Loc, properties)) if isArrayType { p.finishReparsedNode(t, jstypeliteral.AsNode()) t = p.factory.NewArrayTypeNode(t) } p.finishReparsedNode(t, jstypeliteral.AsNode()) } return p.factory.DeepCloneReparse(t) } func (p *Parser) gatherTypeParameters(j *ast.Node, tagWithTypeParameters *ast.Node) *ast.NodeList { var typeParameters []*ast.Node pos := -1 endPos := -1 firstTemplate := true // type parameters only apply to the tag or node they occur before, so record a place to stop start := 0 for i, other := range j.AsJSDoc().Tags.Nodes { if other == tagWithTypeParameters { break } if other.Kind == ast.KindJSDocTypedefTag || other.Kind == ast.KindJSDocCallbackTag || other.Kind == ast.KindJSDocOverloadTag { start = i + 1 } } for i, tag := range j.AsJSDoc().Tags.Nodes { if tag == tagWithTypeParameters { break } if i < start || tag.Kind != ast.KindJSDocTemplateTag { continue } if firstTemplate { pos = tag.Pos() firstTemplate = false } endPos = tag.End() constraint := tag.AsJSDocTemplateTag().Constraint firstTypeParameter := true for _, tp := range tag.TypeParameters() { var reparse *ast.Node if constraint != nil && firstTypeParameter { reparse = p.factory.NewTypeParameterDeclaration( p.factory.DeepCloneReparseModifiers(tp.Modifiers()), p.factory.DeepCloneReparse(tp.Name()), p.factory.DeepCloneReparse(constraint.Type()), p.factory.DeepCloneReparse(tp.AsTypeParameter().DefaultType), ) p.finishReparsedNode(reparse, tp) } else { reparse = p.factory.DeepCloneReparse(tp) } if typeParameters == nil { typeParameters = p.nodeSlicePool.NewSlice(0) } typeParameters = append(typeParameters, reparse) firstTypeParameter = false } } if len(typeParameters) == 0 { return nil } else { return p.newNodeList(core.NewTextRange(pos, endPos), typeParameters) } } func (p *Parser) reparseHosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Node) { switch tag.Kind { case ast.KindJSDocTypeTag: switch parent.Kind { case ast.KindVariableStatement: if parent.AsVariableStatement().DeclarationList != nil { for _, declaration := range parent.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes { if declaration.Type() == nil && tag.AsJSDocTypeTag().TypeExpression != nil { declaration.AsMutable().SetType(p.factory.DeepCloneReparse(tag.AsJSDocTypeTag().TypeExpression.Type())) p.finishMutatedNode(declaration) return } } } case ast.KindVariableDeclaration, ast.KindCommonJSExport, ast.KindExportAssignment, ast.KindJSExportAssignment, ast.KindPropertyDeclaration, ast.KindPropertyAssignment, ast.KindShorthandPropertyAssignment: if parent.Type() == nil && tag.AsJSDocTypeTag().TypeExpression != nil { parent.AsMutable().SetType(p.factory.DeepCloneReparse(tag.AsJSDocTypeTag().TypeExpression.Type())) p.finishMutatedNode(parent) return } case ast.KindParameter: if parent.Type() == nil && tag.AsJSDocTypeTag().TypeExpression != nil { parent.AsMutable().SetType(p.reparseJSDocTypeLiteral(tag.AsJSDocTypeTag().TypeExpression.Type())) p.finishMutatedNode(parent) return } case ast.KindExpressionStatement: if parent.AsExpressionStatement().Expression.Kind == ast.KindBinaryExpression { bin := parent.AsExpressionStatement().Expression.AsBinaryExpression() if kind := ast.GetAssignmentDeclarationKind(bin); kind != ast.JSDeclarationKindNone && tag.AsJSDocTypeTag().TypeExpression != nil { bin.AsMutable().SetType(p.factory.DeepCloneReparse(tag.AsJSDocTypeTag().TypeExpression.Type())) p.finishMutatedNode(bin.AsNode()) return } } case ast.KindReturnStatement, ast.KindParenthesizedExpression: if tag.AsJSDocTypeTag().TypeExpression != nil { parent.AsMutable().SetExpression(p.makeNewCast( p.factory.DeepCloneReparse(tag.AsJSDocTypeTag().TypeExpression.Type()), p.factory.DeepCloneReparse(parent.Expression()), true /*isAssertion*/)) p.finishMutatedNode(parent) return } } if fun, ok := getFunctionLikeHost(parent); ok { noTypedParams := core.Every(fun.Parameters(), func(param *ast.Node) bool { return param.Type() == nil }) if fun.Type() == nil && noTypedParams && tag.AsJSDocTypeTag().TypeExpression != nil { fun.FunctionLikeData().FullSignature = p.factory.DeepCloneReparse(tag.AsJSDocTypeTag().TypeExpression.Type()) p.finishMutatedNode(fun) } } case ast.KindJSDocSatisfiesTag: switch parent.Kind { case ast.KindVariableStatement: if parent.AsVariableStatement().DeclarationList != nil { for _, declaration := range parent.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes { if declaration.Initializer() != nil && tag.AsJSDocSatisfiesTag().TypeExpression != nil { declaration.AsMutable().SetInitializer(p.makeNewCast( p.factory.DeepCloneReparse(tag.AsJSDocSatisfiesTag().TypeExpression.Type()), p.factory.DeepCloneReparse(declaration.Initializer()), false /*isAssertion*/)) p.finishMutatedNode(declaration) break } } } case ast.KindVariableDeclaration, ast.KindCommonJSExport, ast.KindPropertyDeclaration, ast.KindPropertyAssignment, ast.KindShorthandPropertyAssignment: if parent.Initializer() != nil && tag.AsJSDocSatisfiesTag().TypeExpression != nil { parent.AsMutable().SetInitializer(p.makeNewCast( p.factory.DeepCloneReparse(tag.AsJSDocSatisfiesTag().TypeExpression.Type()), p.factory.DeepCloneReparse(parent.Initializer()), false /*isAssertion*/)) p.finishMutatedNode(parent) } case ast.KindReturnStatement, ast.KindParenthesizedExpression, ast.KindExportAssignment, ast.KindJSExportAssignment: if parent.Expression() != nil && tag.AsJSDocSatisfiesTag().TypeExpression != nil { parent.AsMutable().SetExpression(p.makeNewCast( p.factory.DeepCloneReparse(tag.AsJSDocSatisfiesTag().TypeExpression.Type()), p.factory.DeepCloneReparse(parent.Expression()), false /*isAssertion*/)) p.finishMutatedNode(parent) } case ast.KindExpressionStatement: if parent.AsExpressionStatement().Expression.Kind == ast.KindBinaryExpression { bin := parent.AsExpressionStatement().Expression.AsBinaryExpression() if kind := ast.GetAssignmentDeclarationKind(bin); kind != ast.JSDeclarationKindNone && tag.AsJSDocSatisfiesTag().TypeExpression != nil { bin.Right = p.makeNewCast( p.factory.DeepCloneReparse(tag.AsJSDocSatisfiesTag().TypeExpression.Type()), p.factory.DeepCloneReparse(bin.Right), false /*isAssertion*/) p.finishMutatedNode(bin.AsNode()) } } } case ast.KindJSDocTemplateTag: if fun, ok := getFunctionLikeHost(parent); ok { if fun.TypeParameters() == nil { fun.FunctionLikeData().TypeParameters = p.gatherTypeParameters(jsDoc, nil /*tagWithTypeParameters*/) p.finishMutatedNode(fun) } } else if parent.Kind == ast.KindClassDeclaration { class := parent.AsClassDeclaration() if class.TypeParameters == nil { class.TypeParameters = p.gatherTypeParameters(jsDoc, nil /*tagWithTypeParameters*/) p.finishMutatedNode(parent) } } else if parent.Kind == ast.KindClassExpression { class := parent.AsClassExpression() if class.TypeParameters == nil { class.TypeParameters = p.gatherTypeParameters(jsDoc, nil /*tagWithTypeParameters*/) p.finishMutatedNode(parent) } } case ast.KindJSDocParameterTag: if fun, ok := getFunctionLikeHost(parent); ok { parameterTag := tag.AsJSDocParameterOrPropertyTag() if param, ok := findMatchingParameter(fun, parameterTag, jsDoc); ok { if param.Type == nil && parameterTag.TypeExpression != nil { param.AsParameterDeclaration().Type = p.reparseJSDocTypeLiteral(parameterTag.TypeExpression.Type()) } if param.QuestionToken == nil && param.Initializer == nil { if question := p.makeQuestionIfOptional(parameterTag); question != nil { param.QuestionToken = question } } p.finishMutatedNode(param.AsNode()) } } case ast.KindJSDocThisTag: if fun, ok := getFunctionLikeHost(parent); ok { params := fun.Parameters() if len(params) == 0 || params[0].Name().Kind != ast.KindThisKeyword { thisParam := p.factory.NewParameterDeclaration( nil, /* decorators */ nil, /* modifiers */ p.factory.NewIdentifier("this"), nil, /* questionToken */ nil, /* type */ nil, /* initializer */ ) if tag.AsJSDocThisTag().TypeExpression != nil { thisParam.AsParameterDeclaration().Type = p.factory.DeepCloneReparse(tag.AsJSDocThisTag().TypeExpression.Type()) } p.finishReparsedNode(thisParam, tag.AsJSDocThisTag().TagName) newParams := p.nodeSlicePool.NewSlice(len(params) + 1) newParams[0] = thisParam for i, param := range params { newParams[i+1] = param } fun.FunctionLikeData().Parameters = p.newNodeList(thisParam.Loc, newParams) p.finishMutatedNode(fun) } } case ast.KindJSDocReturnTag: if fun, ok := getFunctionLikeHost(parent); ok { if fun.Type() == nil && tag.AsJSDocReturnTag().TypeExpression != nil { fun.FunctionLikeData().Type = p.factory.DeepCloneReparse(tag.AsJSDocReturnTag().TypeExpression.Type()) p.finishMutatedNode(fun) } } case ast.KindJSDocReadonlyTag, ast.KindJSDocPrivateTag, ast.KindJSDocPublicTag, ast.KindJSDocProtectedTag, ast.KindJSDocOverrideTag: if parent.Kind == ast.KindExpressionStatement { parent = parent.AsExpressionStatement().Expression } switch parent.Kind { case ast.KindPropertyDeclaration, ast.KindMethodDeclaration, ast.KindGetAccessor, ast.KindSetAccessor, ast.KindBinaryExpression: var keyword ast.Kind switch tag.Kind { case ast.KindJSDocReadonlyTag: keyword = ast.KindReadonlyKeyword case ast.KindJSDocPrivateTag: keyword = ast.KindPrivateKeyword case ast.KindJSDocPublicTag: keyword = ast.KindPublicKeyword case ast.KindJSDocProtectedTag: keyword = ast.KindProtectedKeyword case ast.KindJSDocOverrideTag: keyword = ast.KindOverrideKeyword } modifier := p.factory.NewModifier(keyword) modifier.Loc = tag.Loc modifier.Flags = p.contextFlags | ast.NodeFlagsReparsed var nodes []*ast.Node var loc core.TextRange if parent.Modifiers() == nil { nodes = p.nodeSlicePool.NewSlice(1) nodes[0] = modifier loc = tag.Loc } else { nodes = append(parent.Modifiers().Nodes, modifier) loc = parent.Modifiers().Loc } parent.AsMutable().SetModifiers(p.newModifierList(loc, nodes)) p.finishMutatedNode(parent) } case ast.KindJSDocImplementsTag: if class := getClassLikeData(parent); class != nil { implementsTag := tag.AsJSDocImplementsTag() if class.HeritageClauses != nil { if implementsClause := core.Find(class.HeritageClauses.Nodes, func(node *ast.Node) bool { return node.AsHeritageClause().Token == ast.KindImplementsKeyword }); implementsClause != nil { implementsClause.AsHeritageClause().Types.Nodes = append(implementsClause.AsHeritageClause().Types.Nodes, p.factory.DeepCloneReparse(implementsTag.ClassName)) p.finishMutatedNode(implementsClause) return } } typesList := p.newNodeList(implementsTag.ClassName.Loc, p.nodeSlicePool.NewSlice1(p.factory.DeepCloneReparse(implementsTag.ClassName))) heritageClause := p.factory.NewHeritageClause(ast.KindImplementsKeyword, typesList) p.finishReparsedNode(heritageClause, implementsTag.ClassName) if class.HeritageClauses == nil { heritageClauses := p.newNodeList(implementsTag.ClassName.Loc, p.nodeSlicePool.NewSlice1(heritageClause)) class.HeritageClauses = heritageClauses } else { class.HeritageClauses.Nodes = append(class.HeritageClauses.Nodes, heritageClause) } p.finishMutatedNode(parent) } case ast.KindJSDocAugmentsTag: if class := getClassLikeData(parent); class != nil && class.HeritageClauses != nil { if extendsClause := core.Find(class.HeritageClauses.Nodes, func(node *ast.Node) bool { return node.AsHeritageClause().Token == ast.KindExtendsKeyword }); extendsClause != nil && len(extendsClause.AsHeritageClause().Types.Nodes) == 1 { target := extendsClause.AsHeritageClause().Types.Nodes[0].AsExpressionWithTypeArguments() source := tag.AsJSDocAugmentsTag().ClassName.AsExpressionWithTypeArguments() if ast.HasSamePropertyAccessName(target.Expression, source.Expression) { if target.TypeArguments == nil && source.TypeArguments != nil { newArguments := p.nodeSlicePool.NewSlice(len(source.TypeArguments.Nodes)) for i, arg := range source.TypeArguments.Nodes { newArguments[i] = p.factory.DeepCloneReparse(arg) } target.TypeArguments = p.newNodeList(source.TypeArguments.Loc, newArguments) p.finishMutatedNode(target.AsNode()) } } } } } } func (p *Parser) makeQuestionIfOptional(parameter *ast.JSDocParameterTag) *ast.Node { var questionToken *ast.Node if parameter.IsBracketed || parameter.TypeExpression != nil && parameter.TypeExpression.Type().Kind == ast.KindJSDocOptionalType { questionToken = p.factory.NewToken(ast.KindQuestionToken) questionToken.Loc = parameter.Loc questionToken.Flags = p.contextFlags | ast.NodeFlagsReparsed } return questionToken } func findMatchingParameter(fun *ast.Node, parameterTag *ast.JSDocParameterTag, jsDoc *ast.Node) (*ast.ParameterDeclaration, bool) { tagIndex := -1 paramCount := -1 for _, tag := range jsDoc.AsJSDoc().Tags.Nodes { if tag.Kind == ast.KindJSDocParameterTag { paramCount++ if tag.AsJSDocParameterOrPropertyTag() == parameterTag { tagIndex = paramCount break } } } for parameterIndex, parameter := range fun.Parameters() { if parameter.Name().Kind == ast.KindIdentifier { if parameterTag.Name().Kind == ast.KindIdentifier && parameter.Name().Text() == parameterTag.Name().Text() { return parameter.AsParameterDeclaration(), true } } else if parameterIndex == tagIndex { return parameter.AsParameterDeclaration(), true } } return nil, false } func getFunctionLikeHost(host *ast.Node) (*ast.Node, bool) { fun := host if host.Kind == ast.KindVariableStatement && host.AsVariableStatement().DeclarationList != nil { for _, declaration := range host.AsVariableStatement().DeclarationList.AsVariableDeclarationList().Declarations.Nodes { if ast.IsFunctionLike(declaration.Initializer()) { fun = declaration.Initializer() break } } } else if host.Kind == ast.KindPropertyAssignment { fun = host.AsPropertyAssignment().Initializer } else if host.Kind == ast.KindPropertyDeclaration { fun = host.AsPropertyDeclaration().Initializer } else if host.Kind == ast.KindExportAssignment { fun = host.AsExportAssignment().Expression } else if host.Kind == ast.KindReturnStatement { fun = host.AsReturnStatement().Expression } if ast.IsFunctionLike(fun) { return fun, true } return nil, false } func (p *Parser) makeNewCast(t *ast.TypeNode, e *ast.Node, isAssertion bool) *ast.Node { var assert *ast.Node if isAssertion { assert = p.factory.NewAsExpression(e, t) } else { assert = p.factory.NewSatisfiesExpression(e, t) } p.finishReparsedNode(assert, e) return assert } func getClassLikeData(parent *ast.Node) *ast.ClassLikeBase { var class *ast.ClassLikeBase switch parent.Kind { case ast.KindClassDeclaration: class = parent.AsClassDeclaration().ClassLikeData() case ast.KindClassExpression: class = parent.AsClassExpression().ClassLikeData() } return class }