diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7f18bbc1a1dec..7638c2527e6dd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -43407,7 +43407,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkJSDocLinkLikeTag(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain) { if (node.name) { - resolveJSDocMemberName(node.name, /*ignoreErrors*/ true); + if (isImportTypeNode(node.name)) { + checkImportType(node.name); + } + else { + resolveJSDocMemberName(node.name, /*ignoreErrors*/ true); + } } } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 694262eeeb54a..12b0668a3b6e8 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -5396,7 +5396,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createJSDocLink(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink { + function createJSDocLink(name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLink { const node = createBaseNode(SyntaxKind.JSDocLink); node.name = name; node.text = text; @@ -5404,14 +5404,14 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocLink(node: JSDocLink, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink { + function updateJSDocLink(node: JSDocLink, name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLink { return node.name !== name ? update(createJSDocLink(name, text), node) : node; } // @api - function createJSDocLinkCode(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode { + function createJSDocLinkCode(name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkCode { const node = createBaseNode(SyntaxKind.JSDocLinkCode); node.name = name; node.text = text; @@ -5419,14 +5419,14 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocLinkCode(node: JSDocLinkCode, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode { + function updateJSDocLinkCode(node: JSDocLinkCode, name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkCode { return node.name !== name ? update(createJSDocLinkCode(name, text), node) : node; } // @api - function createJSDocLinkPlain(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain { + function createJSDocLinkPlain(name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkPlain { const node = createBaseNode(SyntaxKind.JSDocLinkPlain); node.name = name; node.text = text; @@ -5434,7 +5434,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocLinkPlain(node: JSDocLinkPlain, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain { + function updateJSDocLinkPlain(node: JSDocLinkPlain, name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkPlain { return node.name !== name ? update(createJSDocLinkPlain(name, text), node) : node; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 8c69cccba1282..993a64bfcea48 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -9288,8 +9288,10 @@ namespace Parser { function parseJSDocLinkName() { if (tokenIsIdentifierOrKeyword(token())) { + if (token() === SyntaxKind.ImportKeyword) { + return parseImportType(); + } const pos = getNodePos(); - let name: EntityName | JSDocMemberName = parseIdentifierName(); while (parseOptional(SyntaxKind.DotToken)) { name = finishNode(factory.createQualifiedName(name, token() === SyntaxKind.PrivateIdentifier ? createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false) : parseIdentifierName()), pos); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f6ca75a68e17d..67ff0fde99f2f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3951,19 +3951,19 @@ export interface JSDocTag extends Node { export interface JSDocLink extends Node { readonly kind: SyntaxKind.JSDocLink; - readonly name?: EntityName | JSDocMemberName; + readonly name?: EntityName | JSDocMemberName | ImportTypeNode; text: string; } export interface JSDocLinkCode extends Node { readonly kind: SyntaxKind.JSDocLinkCode; - readonly name?: EntityName | JSDocMemberName; + readonly name?: EntityName | JSDocMemberName | ImportTypeNode; text: string; } export interface JSDocLinkPlain extends Node { readonly kind: SyntaxKind.JSDocLinkPlain; - readonly name?: EntityName | JSDocMemberName; + readonly name?: EntityName | JSDocMemberName | ImportTypeNode; text: string; } @@ -9083,12 +9083,12 @@ export interface NodeFactory { updateJSDocNameReference(node: JSDocNameReference, name: EntityName | JSDocMemberName): JSDocNameReference; createJSDocMemberName(left: EntityName | JSDocMemberName, right: Identifier): JSDocMemberName; updateJSDocMemberName(node: JSDocMemberName, left: EntityName | JSDocMemberName, right: Identifier): JSDocMemberName; - createJSDocLink(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink; - updateJSDocLink(node: JSDocLink, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink; - createJSDocLinkCode(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode; - updateJSDocLinkCode(node: JSDocLinkCode, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode; - createJSDocLinkPlain(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain; - updateJSDocLinkPlain(node: JSDocLinkPlain, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain; + createJSDocLink(name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLink; + updateJSDocLink(node: JSDocLink, name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLink; + createJSDocLinkCode(name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkCode; + updateJSDocLinkCode(node: JSDocLinkCode, name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkCode; + createJSDocLinkPlain(name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkPlain; + updateJSDocLinkPlain(node: JSDocLinkPlain, name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkPlain; createJSDocTypeLiteral(jsDocPropertyTags?: readonly JSDocPropertyLikeTag[], isArrayType?: boolean): JSDocTypeLiteral; updateJSDocTypeLiteral(node: JSDocTypeLiteral, jsDocPropertyTags: readonly JSDocPropertyLikeTag[] | undefined, isArrayType: boolean | undefined): JSDocTypeLiteral; createJSDocSignature(typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type?: JSDocReturnTag): JSDocSignature; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5755369134d8a..8e7a31022c329 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -12099,7 +12099,6 @@ export function forEachDynamicImportOrRequireCall { if (child.pos <= position && (position < child.end || (position === child.end && (child.kind === SyntaxKind.EndOfFileToken)))) { @@ -12107,7 +12106,7 @@ function getNodeAtPosition(sourceFile: SourceFile, position: number, includeJSDo } }; while (true) { - const child = isJavaScriptFile && includeJSDoc && hasJSDocNodes(current) && forEach(current.jsDoc, getContainingChild) || forEachChild(current, getContainingChild); + const child = includeJSDoc && hasJSDocNodes(current) && forEach(current.jsDoc, getContainingChild) || forEachChild(current, getContainingChild); if (!child) { return current; } diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 02623678a0cf0..4c8f0f3c1f734 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -88,6 +88,7 @@ import { getLeadingCommentRanges, getLeadingCommentRangesOfNode, getSourceFileOfNode, + getTextOfNode, getTrailingCommentRanges, hasAccessorModifier, HasDecorators, @@ -133,6 +134,7 @@ import { isFunctionTypeNode, isIdentifier, isImportSpecifier, + isImportTypeNode, isInJSFile, isJSDoc, isJSDocAugmentsTag, @@ -1298,7 +1300,7 @@ function formatJSDocLink(link: JSDocLink | JSDocLinkCode | JSDocLinkPlain) { const kind = link.kind === SyntaxKind.JSDocLink ? "link" : link.kind === SyntaxKind.JSDocLinkCode ? "linkcode" : "linkplain"; - const name = link.name ? entityNameToString(link.name) : ""; + const name = link.name ? isImportTypeNode(link.name) ? getTextOfNode(link.name) : entityNameToString(link.name) : ""; const space = link.name && (link.text === "" || link.text.startsWith("://")) ? "" : " "; return `{@${kind} ${name}${space}${link.text}}`; } diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 2531c9ea0413d..1ba7c73b5fcd5 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -5723,17 +5723,17 @@ declare namespace ts { } interface JSDocLink extends Node { readonly kind: SyntaxKind.JSDocLink; - readonly name?: EntityName | JSDocMemberName; + readonly name?: EntityName | JSDocMemberName | ImportTypeNode; text: string; } interface JSDocLinkCode extends Node { readonly kind: SyntaxKind.JSDocLinkCode; - readonly name?: EntityName | JSDocMemberName; + readonly name?: EntityName | JSDocMemberName | ImportTypeNode; text: string; } interface JSDocLinkPlain extends Node { readonly kind: SyntaxKind.JSDocLinkPlain; - readonly name?: EntityName | JSDocMemberName; + readonly name?: EntityName | JSDocMemberName | ImportTypeNode; text: string; } type JSDocComment = JSDocText | JSDocLink | JSDocLinkCode | JSDocLinkPlain; @@ -7763,12 +7763,12 @@ declare namespace ts { updateJSDocNameReference(node: JSDocNameReference, name: EntityName | JSDocMemberName): JSDocNameReference; createJSDocMemberName(left: EntityName | JSDocMemberName, right: Identifier): JSDocMemberName; updateJSDocMemberName(node: JSDocMemberName, left: EntityName | JSDocMemberName, right: Identifier): JSDocMemberName; - createJSDocLink(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink; - updateJSDocLink(node: JSDocLink, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink; - createJSDocLinkCode(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode; - updateJSDocLinkCode(node: JSDocLinkCode, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode; - createJSDocLinkPlain(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain; - updateJSDocLinkPlain(node: JSDocLinkPlain, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain; + createJSDocLink(name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLink; + updateJSDocLink(node: JSDocLink, name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLink; + createJSDocLinkCode(name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkCode; + updateJSDocLinkCode(node: JSDocLinkCode, name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkCode; + createJSDocLinkPlain(name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkPlain; + updateJSDocLinkPlain(node: JSDocLinkPlain, name: EntityName | JSDocMemberName | ImportTypeNode | undefined, text: string): JSDocLinkPlain; createJSDocTypeLiteral(jsDocPropertyTags?: readonly JSDocPropertyLikeTag[], isArrayType?: boolean): JSDocTypeLiteral; updateJSDocTypeLiteral(node: JSDocTypeLiteral, jsDocPropertyTags: readonly JSDocPropertyLikeTag[] | undefined, isArrayType: boolean | undefined): JSDocTypeLiteral; createJSDocSignature(typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type?: JSDocReturnTag): JSDocSignature; diff --git a/tests/baselines/reference/jsdocLink7.baseline b/tests/baselines/reference/jsdocLink7.baseline new file mode 100644 index 0000000000000..df2acd4df5893 --- /dev/null +++ b/tests/baselines/reference/jsdocLink7.baseline @@ -0,0 +1,88 @@ +// === QuickInfo === +=== /b.ts === +// /** +// * {@link import('./a').A} +// */ +// export function f() { } +// ^ +// | ---------------------------------------------------------------------- +// | function f(): void +// | {@link import('./a').A} +// | ---------------------------------------------------------------------- + +[ + { + "marker": { + "fileName": "/b.ts", + "position": 51, + "name": "" + }, + "item": { + "kind": "function", + "kindModifiers": "export", + "textSpan": { + "start": 51, + "length": 1 + }, + "displayParts": [ + { + "text": "function", + "kind": "keyword" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "f", + "kind": "functionName" + }, + { + "text": "(", + "kind": "punctuation" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "void", + "kind": "keyword" + } + ], + "documentation": [ + { + "text": "", + "kind": "text" + }, + { + "text": "{@link ", + "kind": "link" + }, + { + "text": "import('./a').A", + "kind": "linkName", + "target": { + "fileName": "/a.ts", + "textSpan": { + "start": 0, + "length": 24 + } + } + }, + { + "text": "}", + "kind": "link" + } + ] + } + } +] \ No newline at end of file diff --git a/tests/baselines/reference/jsdocLinkTag10.symbols b/tests/baselines/reference/jsdocLinkTag10.symbols new file mode 100644 index 0000000000000..eecc9f49b4935 --- /dev/null +++ b/tests/baselines/reference/jsdocLinkTag10.symbols @@ -0,0 +1,13 @@ +//// [tests/cases/conformance/jsdoc/jsdocLinkTag10.ts] //// + +=== /a.ts === +export interface A {} +>A : Symbol(A, Decl(a.ts, 0, 0)) + +=== /b.ts === +/** + * {@link import('./a').A} + */ +export function fn() { } +>fn : Symbol(fn, Decl(b.ts, 0, 0)) + diff --git a/tests/baselines/reference/jsdocLinkTag10.types b/tests/baselines/reference/jsdocLinkTag10.types new file mode 100644 index 0000000000000..caef430d23695 --- /dev/null +++ b/tests/baselines/reference/jsdocLinkTag10.types @@ -0,0 +1,14 @@ +//// [tests/cases/conformance/jsdoc/jsdocLinkTag10.ts] //// + +=== /a.ts === + +export interface A {} + +=== /b.ts === +/** + * {@link import('./a').A} + */ +export function fn() { } +>fn : () => void +> : ^^^^^^^^^^ + diff --git a/tests/baselines/reference/jsdocLinkTag11.symbols b/tests/baselines/reference/jsdocLinkTag11.symbols new file mode 100644 index 0000000000000..31ed84cb9395b --- /dev/null +++ b/tests/baselines/reference/jsdocLinkTag11.symbols @@ -0,0 +1,13 @@ +//// [tests/cases/conformance/jsdoc/jsdocLinkTag11.ts] //// + +=== /a.js === +export class A {} +>A : Symbol(A, Decl(a.js, 0, 0)) + +=== /b.js === +/** + * {@link import('./a').A} + */ +export function fn() { } +>fn : Symbol(fn, Decl(b.js, 0, 0)) + diff --git a/tests/baselines/reference/jsdocLinkTag11.types b/tests/baselines/reference/jsdocLinkTag11.types new file mode 100644 index 0000000000000..353845bfcd01c --- /dev/null +++ b/tests/baselines/reference/jsdocLinkTag11.types @@ -0,0 +1,15 @@ +//// [tests/cases/conformance/jsdoc/jsdocLinkTag11.ts] //// + +=== /a.js === +export class A {} +>A : A +> : ^ + +=== /b.js === +/** + * {@link import('./a').A} + */ +export function fn() { } +>fn : () => void +> : ^^^^^^^^^^ + diff --git a/tests/cases/conformance/jsdoc/jsdocLinkTag10.ts b/tests/cases/conformance/jsdoc/jsdocLinkTag10.ts new file mode 100644 index 0000000000000..0671f4d497762 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocLinkTag10.ts @@ -0,0 +1,11 @@ +// @noEmit: true +// @module: esnext + +// @filename: /a.ts +export interface A {} + +// @filename: /b.ts +/** + * {@link import('./a').A} + */ +export function fn() { } diff --git a/tests/cases/conformance/jsdoc/jsdocLinkTag11.ts b/tests/cases/conformance/jsdoc/jsdocLinkTag11.ts new file mode 100644 index 0000000000000..eb7ab988235a5 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocLinkTag11.ts @@ -0,0 +1,13 @@ +// @checkJs: true +// @allowJs: true +// @target: esnext +// @noEmit: true + +// @filename: /a.js +export class A {} + +// @filename: /b.js +/** + * {@link import('./a').A} + */ +export function fn() { } diff --git a/tests/cases/fourslash/jsdocLink7.ts b/tests/cases/fourslash/jsdocLink7.ts new file mode 100644 index 0000000000000..15ec9259bb15c --- /dev/null +++ b/tests/cases/fourslash/jsdocLink7.ts @@ -0,0 +1,12 @@ +/// + +// @filename: /a.ts +////export function A() { }; + +// @Filename: /b.ts +/////** +//// * {@link import('./a').A} +//// */ +////export function /**/f() { } + +verify.baselineQuickInfo();