Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -30194,7 +30194,7 @@ func (c *Checker) getSymbolOfNameOrPropertyAccessExpression(name *ast.Node) *ast
return c.getSymbolOfNode(name.Parent)
}

if name.Parent.Kind == ast.KindExportAssignment && ast.IsEntityNameExpression(name) {
if (name.Parent.Kind == ast.KindExportAssignment || name.Parent.Kind == ast.KindJSExportAssignment) && ast.IsEntityNameExpression(name) {
// Even an entity name expression that doesn't resolve as an entityname may still typecheck as a property access expression
success := c.resolveEntityName(
name,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this is code ported since the introduction of JSExportAssignment, I think that means I'll need to make another pass through the source looking for places where all the synthetic kinds need to be handled alongside their non-synthetic peers.

Expand Down
4 changes: 4 additions & 0 deletions internal/parser/jsdoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func (p *Parser) withJSDoc(node *ast.Node, hasJSDoc bool) []*ast.Node {
pos := node.Pos()
for _, comment := range ranges {
if parsed := p.parseJSDocComment(node, comment.Pos(), comment.End(), pos); parsed != nil {
parsed.Parent = node
jsdoc = append(jsdoc, parsed)
pos = parsed.End()
}
Expand Down Expand Up @@ -979,6 +980,9 @@ func (p *Parser) parseTypedefTag(start int, tagName *ast.IdentifierNode, indent

typedefTag := p.factory.NewJSDocTypedefTag(tagName, typeExpression, fullName, comment)
p.finishNodeWithEnd(typedefTag, start, end)
if typeExpression != nil {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nested @typedef pushes the whole syntax from tragedy to loop back around to comedy.

typeExpression.Parent = typedefTag // forcibly overwrite parent potentially set by inner type expression parse
}
return typedefTag
}

Expand Down
57 changes: 47 additions & 10 deletions internal/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ type Parser struct {
jsdocTagCommentsSpace []string
reparseList []*ast.Node
commonJSModuleIndicator *ast.Node

currentParent *ast.Node
}

var viableKeywordSuggestions = scanner.GetViableKeywordSuggestions()
Expand Down Expand Up @@ -353,14 +355,6 @@ func (p *Parser) finishSourceFile(result *ast.SourceFile, isDeclarationFile bool
result.IdentifierCount = p.identifierCount
result.SetJSDocCache(p.jsdocCache)

ast.SetParentInChildren(result.AsNode())
for parent, children := range p.jsdocCache {
for _, child := range children {
child.Parent = parent
ast.SetParentInChildren(child)
}
}

ast.SetExternalModuleIndicator(result, p.opts.ExternalModuleIndicatorOptions)
}

Expand Down Expand Up @@ -466,7 +460,11 @@ func (p *Parser) reparseTopLevelAwait(sourceFile *ast.SourceFile) *ast.Node {
}
}

return p.factory.NewSourceFile(sourceFile.ParseOptions(), p.sourceText, p.newNodeList(sourceFile.Statements.Loc, statements))
result := p.factory.NewSourceFile(sourceFile.ParseOptions(), p.sourceText, p.newNodeList(sourceFile.Statements.Loc, statements))
for _, s := range statements {
s.Parent = result.AsNode() // force (re)set parent to reparsed source file
}
return result
}

func (p *Parser) parseListIndex(kind ParsingContext, parseElement func(p *Parser, index int) *ast.Node) *ast.NodeList {
Expand Down Expand Up @@ -3571,6 +3569,7 @@ func (p *Parser) parseTupleElementType() *ast.TypeNode {
node := p.factory.NewOptionalTypeNode(typeNode.Type())
node.Flags = typeNode.Flags
node.Loc = typeNode.Loc
typeNode.Parent = node
return node
}
return typeNode
Expand Down Expand Up @@ -4692,6 +4691,16 @@ func (p *Parser) parseJsxElementOrSelfClosingElementOrFragment(inExpressionConte
p.finishNodeWithEnd(newClosingElement, end, end)
newLast := p.factory.NewJsxElement(lastChild.AsJsxElement().OpeningElement, lastChild.AsJsxElement().Children, newClosingElement)
p.finishNodeWithEnd(newLast, lastChild.AsJsxElement().OpeningElement.Pos(), end)
// force reset parent pointers from discarded parse result
if lastChild.AsJsxElement().OpeningElement != nil {
lastChild.AsJsxElement().OpeningElement.Parent = newLast
}
if lastChild.AsJsxElement().Children != nil {
for _, c := range lastChild.AsJsxElement().Children.Nodes {
c.Parent = newLast
}
}
newClosingElement.Parent = newLast
children = p.newNodeList(core.NewTextRange(children.Pos(), newLast.End()), append(children.Nodes[0:len(children.Nodes)-1], newLast))
closingElement = lastChild.AsJsxElement().ClosingElement
} else {
Expand All @@ -4708,6 +4717,7 @@ func (p *Parser) parseJsxElementOrSelfClosingElementOrFragment(inExpressionConte
}
result = p.factory.NewJsxElement(opening, children, closingElement)
p.finishNode(result, pos)
closingElement.Parent = result // force reset parent pointers from possibly discarded parse result
case ast.KindJsxOpeningFragment:
result = p.factory.NewJsxFragment(opening, p.parseJsxChildren(opening), p.parseJsxClosingFragment(inExpressionContext))
p.finishNode(result, pos)
Expand Down Expand Up @@ -5315,7 +5325,9 @@ func (p *Parser) parseMemberExpressionRest(pos int, expression *ast.Expression,
if p.isTemplateStartOfTaggedTemplate() {
// Absorb type arguments into TemplateExpression when preceding expression is ExpressionWithTypeArguments
if questionDotToken == nil && ast.IsExpressionWithTypeArguments(expression) {
expression = p.parseTaggedTemplateRest(pos, expression.AsExpressionWithTypeArguments().Expression, questionDotToken, expression.AsExpressionWithTypeArguments().TypeArguments)
original := expression.AsExpressionWithTypeArguments()
expression = p.parseTaggedTemplateRest(pos, original.Expression, questionDotToken, original.TypeArguments)
p.unparseExpressionWithTypeArguments(original.Expression, original.TypeArguments, expression)
} else {
expression = p.parseTaggedTemplateRest(pos, expression, questionDotToken, nil /*typeArguments*/)
}
Expand Down Expand Up @@ -5430,10 +5442,12 @@ func (p *Parser) parseCallExpressionRest(pos int, expression *ast.Expression) *a
typeArguments = expression.AsExpressionWithTypeArguments().TypeArguments
expression = expression.AsExpressionWithTypeArguments().Expression
}
inner := expression
argumentList := p.parseArgumentList()
isOptionalChain := questionDotToken != nil || p.tryReparseOptionalChain(expression)
expression = p.factory.NewCallExpression(expression, questionDotToken, typeArguments, argumentList, core.IfElse(isOptionalChain, ast.NodeFlagsOptionalChain, ast.NodeFlagsNone))
p.finishNode(expression, pos)
p.unparseExpressionWithTypeArguments(inner, typeArguments, expression)
continue
}
if questionDotToken != nil {
Expand Down Expand Up @@ -5714,6 +5728,18 @@ func (p *Parser) parseDecoratedExpression() *ast.Expression {
return result
}

func (p *Parser) unparseExpressionWithTypeArguments(expression *ast.Node, typeArguments *ast.NodeList, result *ast.Node) {
// force overwrite the `.Parent` of the expression and type arguments to erase the fact that they may have originally been parsed as an ExpressionWithTypeArguments and be parented to such
if expression != nil {
expression.Parent = result
}
if typeArguments != nil {
for _, a := range typeArguments.Nodes {
a.Parent = result
}
}
}

func (p *Parser) parseNewExpressionOrNewDotTarget() *ast.Node {
pos := p.nodePos()
p.parseExpected(ast.KindNewKeyword)
Expand All @@ -5740,6 +5766,7 @@ func (p *Parser) parseNewExpressionOrNewDotTarget() *ast.Node {
}
result := p.factory.NewNewExpression(expression, typeArguments, argumentList)
p.finishNode(result, pos)
p.unparseExpressionWithTypeArguments(expression, typeArguments, result)
return result
}

Expand Down Expand Up @@ -5888,6 +5915,16 @@ func (p *Parser) finishNodeWithEnd(node *ast.Node, pos int, end int) {
node.Flags |= ast.NodeFlagsThisNodeHasError
p.hasParseError = false
}
p.currentParent = node
node.ForEachChild(p.setParent)
Comment thread
weswigham marked this conversation as resolved.
Outdated
}

func (p *Parser) setParent(node *ast.Node) bool {
if node.Parent == nil {
node.Parent = p.currentParent
}
// TODO: panic if attempt to overwrite .Parent with new, different .Parent when jsdoc reparser is fixed to not reuse the same nodes in many places
return false
}

func (p *Parser) nextTokenIsSlash() bool {
Expand Down
Loading