620 lines
24 KiB
Go
620 lines
24 KiB
Go
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
|
|
}
|