Skip to content

Commit 842e5d0

Browse files
committed
feat(47558): check JSDoc link tags in TypeScript/JavaScript files
1 parent c06849a commit 842e5d0

File tree

12 files changed

+180
-3
lines changed

12 files changed

+180
-3
lines changed

src/compiler/checker.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36200,6 +36200,10 @@ namespace ts {
3620036200
checkSourceElement(node.typeExpression);
3620136201
}
3620236202

36203+
function checkJSDocLinkLikeTag(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain) {
36204+
checkSourceElement(node.name);
36205+
}
36206+
3620336207
function checkJSDocParameterTag(node: JSDocParameterTag) {
3620436208
checkSourceElement(node.typeExpression);
3620536209
if (!getParameterSymbolFromJSDoc(node)) {
@@ -40347,9 +40351,15 @@ namespace ts {
4034740351
}
4034840352

4034940353
function checkSourceElementWorker(node: Node): void {
40350-
if (isInJSFile(node)) {
40351-
forEach((node as JSDocContainer).jsDoc, ({ tags }) => forEach(tags, checkSourceElement));
40352-
}
40354+
forEach((node as JSDocContainer).jsDoc, ({ comment, tags }) => {
40355+
checkJSDocCommentWorker(comment);
40356+
forEach(tags, tag => {
40357+
checkJSDocCommentWorker(tag.comment);
40358+
if (isInJSFile(node)) {
40359+
checkSourceElement(tag);
40360+
}
40361+
});
40362+
});
4035340363

4035440364
const kind = node.kind;
4035540365
if (cancellationToken) {
@@ -40437,6 +40447,10 @@ namespace ts {
4043740447
return checkJSDocTemplateTag(node as JSDocTemplateTag);
4043840448
case SyntaxKind.JSDocTypeTag:
4043940449
return checkJSDocTypeTag(node as JSDocTypeTag);
40450+
case SyntaxKind.JSDocLink:
40451+
case SyntaxKind.JSDocLinkCode:
40452+
case SyntaxKind.JSDocLinkPlain:
40453+
return checkJSDocLinkLikeTag(node as JSDocLink | JSDocLinkCode | JSDocLinkPlain);
4044040454
case SyntaxKind.JSDocParameterTag:
4044140455
return checkJSDocParameterTag(node as JSDocParameterTag);
4044240456
case SyntaxKind.JSDocPropertyTag:
@@ -40532,6 +40546,16 @@ namespace ts {
4053240546
}
4053340547
}
4053440548

40549+
function checkJSDocCommentWorker(node: string | readonly JSDocComment[] | undefined) {
40550+
if (isArray(node)) {
40551+
forEach(node, tag => {
40552+
if (isJSDocLinkLike(tag)) {
40553+
checkSourceElement(tag);
40554+
}
40555+
});
40556+
}
40557+
}
40558+
4053540559
function checkJSDocTypeIsInJsFile(node: Node): void {
4053640560
if (!isInJSFile(node)) {
4053740561
grammarErrorOnNode(node, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//// [tests/cases/conformance/jsdoc/jsdocLinkTag1.ts] ////
2+
3+
//// [a.ts]
4+
export interface A {}
5+
6+
//// [b.ts]
7+
import type { A } from "./a";
8+
9+
/** {@link A} */
10+
export interface B {}
11+
12+
13+
//// [a.js]
14+
"use strict";
15+
exports.__esModule = true;
16+
//// [b.js]
17+
"use strict";
18+
exports.__esModule = true;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
=== /a.ts ===
2+
export interface A {}
3+
>A : Symbol(A, Decl(a.ts, 0, 0))
4+
5+
=== /b.ts ===
6+
import type { A } from "./a";
7+
>A : Symbol(A, Decl(b.ts, 0, 13))
8+
9+
/** {@link A} */
10+
export interface B {}
11+
>B : Symbol(B, Decl(b.ts, 0, 29))
12+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
=== /a.ts ===
2+
export interface A {}
3+
No type information for this code.
4+
No type information for this code.=== /b.ts ===
5+
import type { A } from "./a";
6+
>A : A
7+
8+
/** {@link A} */
9+
export interface B {}
10+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== /a.js ===
2+
export class A {}
3+
>A : Symbol(A, Decl(a.js, 0, 0))
4+
5+
=== /b.js ===
6+
import { A } from "./a";
7+
>A : Symbol(A, Decl(b.js, 0, 8))
8+
9+
/** {@link A} */
10+
export class B {}
11+
>B : Symbol(B, Decl(b.js, 0, 24))
12+
13+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== /a.js ===
2+
export class A {}
3+
>A : A
4+
5+
=== /b.js ===
6+
import { A } from "./a";
7+
>A : typeof A
8+
9+
/** {@link A} */
10+
export class B {}
11+
>B : B
12+
13+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [tests/cases/conformance/jsdoc/jsdocLinkTag3.ts] ////
2+
3+
//// [a.ts]
4+
export interface A {}
5+
6+
//// [b.ts]
7+
import type { A } from "./a";
8+
9+
/**
10+
* @param {number} a - see {@link A}
11+
*/
12+
export function foo(a: string) {}
13+
14+
15+
//// [a.js]
16+
"use strict";
17+
exports.__esModule = true;
18+
//// [b.js]
19+
"use strict";
20+
exports.__esModule = true;
21+
exports.foo = void 0;
22+
/**
23+
* @param {number} a - see {@link A}
24+
*/
25+
function foo(a) { }
26+
exports.foo = foo;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== /a.ts ===
2+
export interface A {}
3+
>A : Symbol(A, Decl(a.ts, 0, 0))
4+
5+
=== /b.ts ===
6+
import type { A } from "./a";
7+
>A : Symbol(A, Decl(b.ts, 0, 13))
8+
9+
/**
10+
* @param {number} a - see {@link A}
11+
*/
12+
export function foo(a: string) {}
13+
>foo : Symbol(foo, Decl(b.ts, 0, 29))
14+
>a : Symbol(a, Decl(b.ts, 5, 20))
15+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== /a.ts ===
2+
export interface A {}
3+
No type information for this code.
4+
No type information for this code.=== /b.ts ===
5+
import type { A } from "./a";
6+
>A : A
7+
8+
/**
9+
* @param {number} a - see {@link A}
10+
*/
11+
export function foo(a: string) {}
12+
>foo : (a: string) => void
13+
>a : string
14+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @filename: /a.ts
2+
export interface A {}
3+
4+
// @filename: /b.ts
5+
import type { A } from "./a";
6+
7+
/** {@link A} */
8+
export interface B {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// @target: esnext
2+
// @allowJs: true
3+
// @checkJs: true
4+
// @noEmit: true
5+
6+
// @filename: /a.js
7+
export class A {}
8+
9+
// @filename: /b.js
10+
import { A } from "./a";
11+
12+
/** {@link A} */
13+
export class B {}
14+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// @filename: /a.ts
2+
export interface A {}
3+
4+
// @filename: /b.ts
5+
import type { A } from "./a";
6+
7+
/**
8+
* @param {number} a - see {@link A}
9+
*/
10+
export function foo(a: string) {}

0 commit comments

Comments
 (0)