Skip to content

Commit d025c17

Browse files
committed
fix(2632): allow missing names in jsdoc param tags
1 parent 3ba1ef8 commit d025c17

3 files changed

Lines changed: 24 additions & 15 deletions

File tree

internal/parser/jsdoc.go

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ func (p *Parser) parseTag(tags []*ast.Node, margin int) *ast.Node {
431431
start := p.scanner.TokenStart()
432432
p.nextTokenJSDoc()
433433

434-
tagName := p.parseJSDocIdentifierName(nil)
434+
tagName := p.parseJSDocIdentifierName(diagnostics.Identifier_expected)
435435
indentText := p.skipWhitespaceOrAsterisk()
436436

437437
var tag *ast.Node
@@ -718,15 +718,15 @@ func (p *Parser) tryParseTypeExpression() *ast.Node {
718718
}
719719
}
720720

721-
func (p *Parser) parseBracketNameInPropertyAndParamTag() (name *ast.EntityName, isBracketed bool) {
721+
func (p *Parser) parseBracketNameInPropertyAndParamTag(target propertyLikeParse) (name *ast.EntityName, isBracketed bool) {
722722
// Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar'
723723
isBracketed = p.parseOptionalJsdoc(ast.KindOpenBracketToken)
724724
if isBracketed {
725725
p.skipWhitespace()
726726
}
727727
// a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild
728728
isBackquoted := p.parseOptionalJsdoc(ast.KindBacktickToken)
729-
name = p.parseJSDocEntityName()
729+
name = p.parseJSDocEntityName(core.IfElse(target == propertyLikeParseParameter, nil, diagnostics.Identifier_expected))
730730
if isBackquoted {
731731
p.parseExpectedTokenJSDoc(ast.KindBacktickToken)
732732
}
@@ -763,7 +763,7 @@ func (p *Parser) parseParameterOrPropertyTag(start int, tagName *ast.IdentifierN
763763
isNameFirst := typeExpression == nil
764764
p.skipWhitespaceOrAsterisk()
765765

766-
name, isBracketed := p.parseBracketNameInPropertyAndParamTag()
766+
name, isBracketed := p.parseBracketNameInPropertyAndParamTag(target)
767767
indentText := p.skipWhitespaceOrAsterisk()
768768

769769
if isNameFirst && p.lookAhead(func(p *Parser) bool { _, ok := p.parseJSDocLinkPrefix(); return !ok }) {
@@ -894,9 +894,9 @@ func (p *Parser) parseExpressionWithTypeArgumentsForAugments() *ast.Node {
894894

895895
func (p *Parser) parsePropertyAccessEntityNameExpression() *ast.Node {
896896
pos := p.nodePos()
897-
node := p.parseJSDocIdentifierName(nil)
897+
node := p.parseJSDocIdentifierName(diagnostics.Identifier_expected)
898898
for p.parseOptional(ast.KindDotToken) {
899-
name := p.parseJSDocIdentifierName(nil)
899+
name := p.parseJSDocIdentifierName(diagnostics.Identifier_expected)
900900
node = p.finishNode(p.factory.NewPropertyAccessExpression(node, nil, name, ast.NodeFlagsNone), pos)
901901
}
902902
return node
@@ -916,7 +916,7 @@ func (p *Parser) parseThisTag(start int, tagName *ast.IdentifierNode, margin int
916916
func (p *Parser) parseTypedefTag(start int, tagName *ast.IdentifierNode, indent int, indentText string) *ast.Node {
917917
typeExpression := p.tryParseTypeExpression()
918918
p.skipWhitespaceOrAsterisk()
919-
fullName := p.parseJSDocIdentifierName(nil)
919+
fullName := p.parseJSDocIdentifierName(diagnostics.Identifier_expected)
920920
p.skipWhitespace()
921921
comment := p.parseTagComments(indent, nil)
922922

@@ -1032,7 +1032,7 @@ func (p *Parser) parseJSDocSignature(start int, indent int) *ast.Node {
10321032
}
10331033

10341034
func (p *Parser) parseCallbackTag(start int, tagName *ast.IdentifierNode, indent int, indentText string) *ast.Node {
1035-
fullName := p.parseJSDocIdentifierName(nil)
1035+
fullName := p.parseJSDocIdentifierName(diagnostics.Identifier_expected)
10361036
p.skipWhitespace()
10371037
comment := p.parseTagComments(indent, nil)
10381038
typeExpression := p.parseJSDocSignature(p.nodePos(), indent)
@@ -1119,7 +1119,7 @@ func (p *Parser) tryParseChildTag(target propertyLikeParse, indent int) *ast.Nod
11191119
start := p.scanner.TokenFullStart()
11201120
p.nextTokenJSDoc()
11211121

1122-
tagName := p.parseJSDocIdentifierName(nil)
1122+
tagName := p.parseJSDocIdentifierName(diagnostics.Identifier_expected)
11231123
indentText := p.skipWhitespaceOrAsterisk()
11241124
var t propertyLikeParse
11251125
switch tagName.Text() {
@@ -1212,16 +1212,16 @@ func (p *Parser) parseOptionalJsdoc(t ast.Kind) bool {
12121212
return false
12131213
}
12141214

1215-
func (p *Parser) parseJSDocEntityName() *ast.EntityName {
1216-
var entity *ast.EntityName = p.parseJSDocIdentifierName(nil)
1215+
func (p *Parser) parseJSDocEntityName(diagnosticMessage *diagnostics.Message) *ast.EntityName {
1216+
var entity *ast.EntityName = p.parseJSDocIdentifierName(diagnosticMessage)
12171217
if p.parseOptional(ast.KindOpenBracketToken) {
12181218
p.parseExpected(ast.KindCloseBracketToken)
12191219
// Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking.
12201220
// Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}>
12211221
// but it's not worth it to enforce that restriction.
12221222
}
12231223
for p.parseOptional(ast.KindDotToken) {
1224-
name := p.parseJSDocIdentifierName(nil)
1224+
name := p.parseJSDocIdentifierName(diagnostics.Identifier_expected)
12251225
if p.parseOptional(ast.KindOpenBracketToken) {
12261226
p.parseExpected(ast.KindCloseBracketToken)
12271227
}
@@ -1237,8 +1237,6 @@ func (p *Parser) parseJSDocIdentifierName(diagnosticMessage *diagnostics.Message
12371237
p.parseErrorAtCurrentToken(diagnosticMessage)
12381238
} else if isReservedWord(p.token) {
12391239
p.parseErrorAtCurrentToken(diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, p.scanner.TokenText())
1240-
} else {
1241-
p.parseErrorAtCurrentToken(diagnostics.Identifier_expected)
12421240
}
12431241
return p.finishNode(p.newIdentifier(""), p.nodePos())
12441242
}

internal/parser/reparser.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,8 @@ func findMatchingParameter(fun *ast.Node, parameterTag *ast.JSDocParameterTag, j
588588
}
589589
for parameterIndex, parameter := range fun.Parameters() {
590590
if parameter.Name().Kind == ast.KindIdentifier {
591-
if parameterTag.Name().Kind == ast.KindIdentifier && parameter.Name().Text() == parameterTag.Name().Text() {
591+
if parameterTag.Name().Kind == ast.KindIdentifier &&
592+
((parameter.Name().Text() == parameterTag.Name().Text()) || (parameterIndex == tagIndex && len(parameterTag.Name().Text()) == 0)) {
592593
return parameter.AsParameterDeclaration(), true
593594
}
594595
} else if parameterIndex == tagIndex {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// @allowJs: true
2+
// @checkJs: true
3+
// @noEmit: true
4+
// @filename: a.js
5+
/**
6+
* @param {(x: string) => string}
7+
*/
8+
function foo(f) {
9+
return f(123);
10+
}

0 commit comments

Comments
 (0)