Skip to content

Commit 3f66a41

Browse files
committed
fix(1196): extend parameter matching with index fallback when name matching fails
1 parent 264347f commit 3f66a41

File tree

98 files changed

+852
-1135
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+852
-1135
lines changed

internal/parser/reparser.go

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,11 @@ func (p *Parser) reparseJSDocSignature(jsSignature *ast.Node, fun *ast.Node, jsD
171171
}
172172

173173
func (p *Parser) reparseJSDocTypeLiteral(t *ast.TypeNode, host *ast.Node) *ast.Node {
174-
if t != nil && t.Kind == ast.KindJSDocTypeLiteral {
174+
if t == nil {
175+
return nil
176+
}
177+
if t.Kind == ast.KindJSDocTypeLiteral {
178+
isArrayType := t.AsJSDocTypeLiteral().IsArrayType
175179
properties := p.nodeSlicePool.NewSlice(0)
176180
for _, prop := range t.AsJSDocTypeLiteral().JSDocPropertyTags {
177181
jsprop := prop.AsJSDocParameterOrPropertyTag()
@@ -180,7 +184,9 @@ func (p *Parser) reparseJSDocTypeLiteral(t *ast.TypeNode, host *ast.Node) *ast.N
180184
name = name.AsQualifiedName().Right
181185
}
182186
property := p.factory.NewPropertySignatureDeclaration(nil, name, p.makeQuestionIfOptional(jsprop), nil, nil)
183-
property.AsPropertySignatureDeclaration().Type = p.reparseJSDocTypeLiteral(jsprop.TypeExpression, property)
187+
if jsprop.TypeExpression != nil {
188+
property.AsPropertySignatureDeclaration().Type = p.reparseJSDocTypeLiteral(jsprop.TypeExpression.Type(), property)
189+
}
184190
property.Loc = prop.Loc
185191
property.Flags = p.contextFlags | ast.NodeFlagsReparsed
186192
properties = append(properties, property)
@@ -189,6 +195,11 @@ func (p *Parser) reparseJSDocTypeLiteral(t *ast.TypeNode, host *ast.Node) *ast.N
189195
t = p.factory.NewTypeLiteralNode(p.newNodeList(loc, properties))
190196
t.Loc = loc
191197
t.Flags = p.contextFlags | ast.NodeFlagsReparsed
198+
if isArrayType {
199+
t = p.factory.NewArrayTypeNode(t)
200+
t.Flags = p.contextFlags | ast.NodeFlagsReparsed
201+
t.Loc = loc
202+
}
192203
}
193204
return t
194205
}
@@ -327,13 +338,17 @@ func (p *Parser) reparseHosted(tag *ast.Node, parent *ast.Node, jsDoc *ast.Node)
327338
}
328339
case ast.KindJSDocParameterTag:
329340
if fun, ok := getFunctionLikeHost(parent); ok {
330-
jsparam := tag.AsJSDocParameterOrPropertyTag()
331-
if param, ok := findMatchingParameter(fun, jsparam); ok {
341+
parameterTag := tag.AsJSDocParameterOrPropertyTag()
342+
if param, ok := findMatchingParameter(fun, parameterTag, jsDoc); ok {
332343
if param.Type == nil {
333-
param.Type = setHost(jsparam.TypeExpression, param.AsNode())
344+
paramType := setHost(parameterTag.TypeExpression, param.AsNode())
345+
if parameterTag.IsNameFirst && parameterTag.TypeExpression != nil && parameterTag.TypeExpression.Type().Kind == ast.KindJSDocTypeLiteral {
346+
paramType = p.reparseJSDocTypeLiteral(parameterTag.TypeExpression.Type(), param.AsNode())
347+
}
348+
param.AsParameterDeclaration().Type = paramType
334349
}
335350
if param.QuestionToken == nil && param.Initializer == nil {
336-
if question := p.makeQuestionIfOptional(jsparam); question != nil {
351+
if question := p.makeQuestionIfOptional(parameterTag); question != nil {
337352
param.QuestionToken = question
338353
}
339354
}
@@ -461,11 +476,19 @@ func (p *Parser) makeQuestionIfOptional(parameter *ast.JSDocParameterTag) *ast.N
461476
return questionToken
462477
}
463478

464-
func findMatchingParameter(fun *ast.Node, tag *ast.JSDocParameterTag) (*ast.ParameterDeclaration, bool) {
465-
for _, parameter := range fun.Parameters() {
466-
if parameter.Name().Kind == ast.KindIdentifier && tag.Name().Kind == ast.KindIdentifier &&
467-
parameter.Name().Text() == tag.Name().Text() {
468-
return parameter.AsParameterDeclaration(), true
479+
func findMatchingParameter(fun *ast.Node, tag *ast.JSDocParameterTag, jsDoc *ast.Node) (*ast.ParameterDeclaration, bool) {
480+
tagIndex := core.FindIndex(jsDoc.AsJSDoc().Tags.Nodes, func(n *ast.Node) bool {
481+
return n.Kind == ast.KindJSDocParameterTag && n.AsJSDocParameterOrPropertyTag() == tag
482+
})
483+
for parameterIndex, parameter := range fun.Parameters() {
484+
if parameter.Name().Kind == ast.KindIdentifier {
485+
if tag.Name().Kind == ast.KindIdentifier && parameter.Name().Text() == tag.Name().Text() {
486+
return parameter.AsParameterDeclaration(), true
487+
}
488+
} else {
489+
if parameterIndex == tagIndex {
490+
return parameter.AsParameterDeclaration(), true
491+
}
469492
}
470493
}
471494
return nil, false

testdata/baselines/reference/conformance/jsdocParseAwait.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ const a = 1;
1414
/** @type {T} */
1515
const b = {
1616
>b : T
17-
>{ await: false,} : { await: boolean; }
17+
>{ await: false,} : { await: false; }
1818

1919
await: false,
20-
>await : boolean
20+
>await : false
2121
>false : false
2222

2323
};

testdata/baselines/reference/submodule/compiler/checkJsdocTypeTagOnExportAssignment8.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111

1212
/** @type {Foo} */
1313
export default {
14-
>{ a: 'a', b: 'b'} : { a: string; b: string; }
14+
>{ a: 'a', b: 'b'} : { a: string; b: "b"; }
1515

1616
a: 'a',
1717
>a : string
1818
>'a' : "a"
1919

2020
b: 'b'
21-
>b : string
21+
>b : "b"
2222
>'b' : "b"
2323
}
2424

testdata/baselines/reference/submodule/compiler/declarationEmitClassSetAccessorParamNameInJs2.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ export class Foo {
1010
* @param {{ prop: string }} baz Baz.
1111
*/
1212
set bar({}) {}
13-
>bar : any
13+
>bar : { prop: string; }
1414
}
1515

testdata/baselines/reference/submodule/compiler/declarationEmitClassSetAccessorParamNameInJs3.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export class Foo {
1010
* @param {{ prop: string | undefined }} baz Baz.
1111
*/
1212
set bar({ prop = 'foo' }) {}
13-
>bar : any
13+
>bar : { prop: string; }
1414
>prop : string
1515
>'foo' : "foo"
1616
}

testdata/baselines/reference/submodule/compiler/jsDeclarationEmitDoesNotRenameImport.types

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,19 @@ class X extends Test {
4040
>super : typeof Test
4141

4242
if (options.test) {
43-
>options.test : any
43+
>options.test : typeof import("./Test.js").default | undefined
4444
>options : Options
45-
>test : any
45+
>test : typeof import("./Test.js").default | undefined
4646

4747
this.test = new options.test();
48-
>this.test = new options.test() : any
48+
>this.test = new options.test() : import("./Test.js").default
4949
>this.test : any
5050
>this : this
5151
>test : any
52-
>new options.test() : any
53-
>options.test : any
52+
>new options.test() : import("./Test.js").default
53+
>options.test : typeof import("./Test.js").default
5454
>options : Options
55-
>test : any
55+
>test : typeof import("./Test.js").default
5656
}
5757
}
5858
}

testdata/baselines/reference/submodule/compiler/jsdocParamTagInvalid.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
=== /a.js ===
44
/** @param {string} colour */
55
function f(color) {}
6-
>f : (color: any) => void
7-
>color : any
6+
>f : (color: string) => void
7+
>color : string
88

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/a.js(3,15): error TS2552: Cannot find name 'sting'. Did you mean 'string'?
2+
3+
4+
==== /a.js (1 errors) ====
5+
/**
6+
* @typedef MyType
7+
* @property {sting} [x]
8+
~~~~~
9+
!!! error TS2552: Cannot find name 'sting'. Did you mean 'string'?
10+
*/
11+
12+
/** @param {MyType} p */
13+
export function f(p) { }
14+
15+
==== /b.js (0 errors) ====
16+
import { f } from "./a.js"
17+
f({ x: 42 })
18+

testdata/baselines/reference/submodule/compiler/strictOptionalProperties3.errors.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
1+
a.js(7,7): error TS2375: Type '{ value: undefined; }' is not assignable to type 'A' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
2+
Types of property 'value' are incompatible.
3+
Type 'undefined' is not assignable to type 'number'.
14
a.js(14,7): error TS2375: Type '{ value: undefined; }' is not assignable to type '{ value?: number; }' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
25
Types of property 'value' are incompatible.
36
Type 'undefined' is not assignable to type 'number'.
47

58

6-
==== a.js (1 errors) ====
9+
==== a.js (2 errors) ====
710
/**
811
* @typedef {object} A
912
* @property {number} [value]
1013
*/
1114

1215
/** @type {A} */
1316
const a = { value: undefined }; // error
17+
~
18+
!!! error TS2375: Type '{ value: undefined; }' is not assignable to type 'A' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
19+
!!! error TS2375: Types of property 'value' are incompatible.
20+
!!! error TS2375: Type 'undefined' is not assignable to type 'number'.
1421

1522
/**
1623
* @typedef {{ value?: number }} B

testdata/baselines/reference/submodule/compiler/strictOptionalProperties4.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@ const x = /** @type {Foo} */ ({});
1212
>{} : {}
1313

1414
x.foo; // number | undefined
15-
>x.foo : any
15+
>x.foo : number | undefined
1616
>x : Foo
17-
>foo : any
17+
>foo : number | undefined
1818

1919
const y = /** @type {Required<Foo>} */ ({});
2020
>y : Required<Foo>
2121
>({}) : Required<Foo>
2222
>{} : {}
2323

2424
y.foo; // number
25-
>y.foo : any
25+
>y.foo : number
2626
>y : Required<Foo>
27-
>foo : any
27+
>foo : number
2828

0 commit comments

Comments
 (0)