Skip to content

Commit 17d7e16

Browse files
committed
fix(1196): extend parameter matching with index fallback when name matching fails
1 parent 60d0c08 commit 17d7e16

File tree

98 files changed

+850
-1133
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

+850
-1133
lines changed

internal/parser/reparser.go

Lines changed: 32 additions & 9 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,13 +476,21 @@ 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) {
479+
func findMatchingParameter(fun *ast.Node, tag *ast.JSDocParameterTag, jsDoc *ast.Node) (*ast.ParameterDeclaration, bool) {
465480
for _, parameter := range fun.Parameters() {
466-
if parameter.Name().Kind == ast.KindIdentifier && tag.Name().Kind == ast.KindIdentifier &&
467-
parameter.Name().Text() == tag.Name().Text() {
481+
if parameter.Name().Kind == ast.KindIdentifier && tag.Name().Kind == ast.KindIdentifier && parameter.Name().Text() == tag.Name().Text() {
468482
return parameter.AsParameterDeclaration(), true
469483
}
470484
}
485+
486+
index := core.FindIndex(jsDoc.AsJSDoc().Tags.Nodes, func(n *ast.Node) bool {
487+
return n.Kind == ast.KindJSDocParameterTag && n.AsJSDocParameterOrPropertyTag() == tag
488+
})
489+
490+
if index < len(fun.Parameters()) {
491+
return fun.Parameters()[index].AsParameterDeclaration(), true
492+
}
493+
471494
return nil, false
472495
}
473496

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

testdata/baselines/reference/submodule/conformance/checkJsdocSatisfiesTag1.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ const t3 = /** @satisfies {T1} */ ({});
4444
/** @type {T2} */
4545
const t4 = /** @satisfies {T2} */ ({ a: "a" });
4646
>t4 : T2
47-
>({ a: "a" }) : { a: string; }
48-
>{ a: "a" } : { a: string; }
49-
>a : string
47+
>({ a: "a" }) : { a: "a"; }
48+
>{ a: "a" } : { a: "a"; }
49+
>a : "a"
5050
>"a" : "a"
5151

5252
/** @type {(m: string) => string} */

testdata/baselines/reference/submodule/conformance/checkJsdocTypedefInParamTag1.types

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ function foo(opts) {
1616
>opts : Opts
1717

1818
opts.x;
19-
>opts.x : any
19+
>opts.x : string
2020
>opts : Opts
21-
>x : any
21+
>x : string
2222
}
2323

2424
foo({x: 'abc'});
@@ -40,9 +40,9 @@ function foo1(opts) {
4040
>opts : AnotherOpts
4141

4242
opts.anotherX;
43-
>opts.anotherX : any
43+
>opts.anotherX : string
4444
>opts : AnotherOpts
45-
>anotherX : any
45+
>anotherX : string
4646
}
4747

4848
foo1({anotherX: "world"});
@@ -66,9 +66,9 @@ function foo2(opts) {
6666
>opts : Opts1
6767

6868
opts.x;
69-
>opts.x : any
69+
>opts.x : string
7070
>opts : Opts1
71-
>x : any
71+
>x : string
7272
}
7373
foo2({x: 'abc'});
7474
>foo2({x: 'abc'}) : void

testdata/baselines/reference/submodule/conformance/destructuringParameterDeclaration9(strict=false).symbols

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function prepareConfig({
99
>prepareConfig : Symbol(prepareConfig, Decl(index.js, 0, 0))
1010

1111
additionalFiles: {
12-
>additionalFiles : Symbol(additionalFiles)
12+
>additionalFiles : Symbol(additionalFiles, Decl(index.js, 2, 3))
1313

1414
json = []
1515
>json : Symbol(json, Decl(index.js, 5, 22))
@@ -60,7 +60,7 @@ export const prepareConfigWithContextualSignature = ({
6060
*/
6161
function f1({ a: { json = [] } = {} } = {}) { return json }
6262
>f1 : Symbol(f1, Decl(index.js, 29, 1))
63-
>a : Symbol(a)
63+
>a : Symbol(a, Decl(index.js, 34, 12))
6464
>json : Symbol(json, Decl(index.js, 36, 18))
6565
>json : Symbol(json, Decl(index.js, 36, 18))
6666

testdata/baselines/reference/submodule/conformance/destructuringParameterDeclaration9(strict=false).symbols.diff

Lines changed: 0 additions & 19 deletions
This file was deleted.

testdata/baselines/reference/submodule/conformance/destructuringParameterDeclaration9(strict=false).types

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
* @param {Partial<Record<'json' | 'jsonc' | 'json5', string[]>>} [config.additionalFiles]
77
*/
88
export function prepareConfig({
9-
>prepareConfig : ({ additionalFiles: { json } }?: { additionalFiles?: { json?: any[]; }; }) => void
9+
>prepareConfig : ({ additionalFiles: { json } }?: { additionalFiles?: Partial<Record<"json" | "json5" | "jsonc", string[]>>; }) => void
1010

1111
additionalFiles: {
1212
>additionalFiles : any
1313

1414
json = []
15-
>json : any[]
15+
>json : string[]
1616
>[] : undefined[]
1717

1818
} = {}
@@ -22,7 +22,7 @@ export function prepareConfig({
2222
>{} : {}
2323

2424
json // string[]
25-
>json : any[]
25+
>json : string[]
2626
}
2727

2828
export function prepareConfigWithoutAnnotation({
@@ -75,22 +75,22 @@ export const prepareConfigWithContextualSignature = ({
7575
* @param {{ a?: { json?: string[] }}} [config]
7676
*/
7777
function f1({ a: { json = [] } = {} } = {}) { return json }
78-
>f1 : ({ a: { json } }?: { a?: { json?: any[]; }; }) => any[]
78+
>f1 : ({ a: { json } }?: { a?: { json?: string[]; }; }) => string[]
7979
>a : any
80-
>json : any[]
80+
>json : string[]
8181
>[] : undefined[]
8282
>{} : {}
8383
>{} : {}
84-
>json : any[]
84+
>json : string[]
8585

8686
/**
8787
* @param {[[string[]?]?]} [x]
8888
*/
8989
function f2([[json = []] = []] = []) { return json }
90-
>f2 : ([[json]]?: [[any[]?]?]) => any[]
91-
>json : any[]
90+
>f2 : ([[json]]?: [[string[]?]?]) => string[]
91+
>json : string[]
9292
>[] : undefined[]
9393
>[] : []
9494
>[] : []
95-
>json : any[]
95+
>json : string[]
9696

testdata/baselines/reference/submodule/conformance/destructuringParameterDeclaration9(strict=true).symbols

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function prepareConfig({
99
>prepareConfig : Symbol(prepareConfig, Decl(index.js, 0, 0))
1010

1111
additionalFiles: {
12-
>additionalFiles : Symbol(additionalFiles)
12+
>additionalFiles : Symbol(additionalFiles, Decl(index.js, 2, 3))
1313

1414
json = []
1515
>json : Symbol(json, Decl(index.js, 5, 22))
@@ -60,7 +60,7 @@ export const prepareConfigWithContextualSignature = ({
6060
*/
6161
function f1({ a: { json = [] } = {} } = {}) { return json }
6262
>f1 : Symbol(f1, Decl(index.js, 29, 1))
63-
>a : Symbol(a)
63+
>a : Symbol(a, Decl(index.js, 34, 12))
6464
>json : Symbol(json, Decl(index.js, 36, 18))
6565
>json : Symbol(json, Decl(index.js, 36, 18))
6666

0 commit comments

Comments
 (0)