Skip to content

JSDoc overload tag #51234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ import {
JSDocClassTag,
JSDocEnumTag,
JSDocFunctionType,
JSDocOverloadTag,
JSDocParameterTag,
JSDocPropertyLikeTag,
JSDocSignature,
Expand Down Expand Up @@ -3027,6 +3028,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
case SyntaxKind.JSDocCallbackTag:
case SyntaxKind.JSDocEnumTag:
return (delayedTypeAliases || (delayedTypeAliases = [])).push(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag);
case SyntaxKind.JSDocOverloadTag:
return bind((node as JSDocOverloadTag).typeExpression);
}
}

Expand Down
17 changes: 17 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ import {
isJSDocNullableType,
isJSDocOptionalParameter,
isJSDocOptionalType,
isJSDocOverloadTag,
isJSDocParameterTag,
isJSDocPropertyLikeTag,
isJSDocPropertyTag,
Expand Down Expand Up @@ -14276,6 +14277,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
continue;
}
}
if (isInJSFile(decl) && decl.jsDoc) {
let hasJSDocOverloads = false;
for (const node of decl.jsDoc) {
if (node.tags) {
for (const tag of node.tags) {
if (isJSDocOverloadTag(tag)) {
result.push(getSignatureFromDeclaration(tag.typeExpression));
hasJSDocOverloads = true;
}
}
}
}
if (hasJSDocOverloads) {
continue;
}
}
// If this is a function or method declaration, get the signature from the @type tag for the sake of optional parameters.
// Exclude contextually-typed kinds because we already apply the @type tag to the context, plus applying it here to the initializer would supress checks that the two are compatible.
result.push(
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ import {
JSDocNonNullableType,
JSDocNullableType,
JSDocOptionalType,
JSDocOverloadTag,
JSDocPropertyLikeTag,
JSDocReturnTag,
JSDocSeeTag,
Expand Down Expand Up @@ -2114,6 +2115,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
return;
case SyntaxKind.JSDocCallbackTag:
return emitJSDocCallbackTag(node as JSDocCallbackTag);
case SyntaxKind.JSDocOverloadTag:
return emitJSDocOverloadTag(node as JSDocOverloadTag);
// SyntaxKind.JSDocEnumTag (see below)
case SyntaxKind.JSDocParameterTag:
case SyntaxKind.JSDocPropertyTag:
Expand Down Expand Up @@ -4373,6 +4376,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
emitJSDocSignature(tag.typeExpression);
}

function emitJSDocOverloadTag(tag: JSDocOverloadTag) {
emitJSDocComment(tag.comment);
emitJSDocSignature(tag.typeExpression);
}

function emitJSDocSimpleTag(tag: JSDocTag) {
emitJSDocTagName(tag.tagName);
emitJSDocComment(tag.comment);
Expand Down
20 changes: 20 additions & 0 deletions src/compiler/factory/nodeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ import {
JSDocNonNullableType,
JSDocNullableType,
JSDocOptionalType,
JSDocOverloadTag,
JSDocOverrideTag,
JSDocParameterTag,
JSDocPrivateTag,
Expand Down Expand Up @@ -831,6 +832,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
updateJSDocPropertyTag,
createJSDocCallbackTag,
updateJSDocCallbackTag,
createJSDocOverloadTag,
updateJSDocOverloadTag,
createJSDocAugmentsTag,
updateJSDocAugmentsTag,
createJSDocImplementsTag,
Expand Down Expand Up @@ -5161,6 +5164,22 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
: node;
}

// @api
function createJSDocOverloadTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, comment?: string | NodeArray<JSDocComment>): JSDocOverloadTag {
const node = createBaseJSDocTag<JSDocOverloadTag>(SyntaxKind.JSDocOverloadTag, tagName ?? createIdentifier("overload"), comment);
node.typeExpression = typeExpression;
return node;
}

// @api
function updateJSDocOverloadTag(node: JSDocOverloadTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocSignature, comment: string | NodeArray<JSDocComment> | undefined): JSDocOverloadTag {
return node.tagName !== tagName
|| node.typeExpression !== typeExpression
|| node.comment !== comment
? update(createJSDocOverloadTag(tagName, typeExpression, comment), node)
: node;
}

// @api
function createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocAugmentsTag {
const node = createBaseJSDocTag<JSDocAugmentsTag>(SyntaxKind.JSDocAugmentsTag, tagName ?? createIdentifier("augments"), comment);
Expand Down Expand Up @@ -6870,6 +6889,7 @@ function getDefaultTagNameForKind(kind: JSDocTag["kind"]): string {
case SyntaxKind.JSDocParameterTag: return "param";
case SyntaxKind.JSDocPropertyTag: return "prop";
case SyntaxKind.JSDocCallbackTag: return "callback";
case SyntaxKind.JSDocOverloadTag: return "overload";
case SyntaxKind.JSDocAugmentsTag: return "augments";
case SyntaxKind.JSDocImplementsTag: return "implements";
default:
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/factory/nodeTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import {
JSDocNonNullableType,
JSDocNullableType,
JSDocOptionalType,
JSDocOverloadTag,
JSDocOverrideTag,
JSDocParameterTag,
JSDocPrivateTag,
Expand Down Expand Up @@ -1129,6 +1130,10 @@ export function isJSDocOverrideTag(node: Node): node is JSDocOverrideTag {
return node.kind === SyntaxKind.JSDocOverrideTag;
}

export function isJSDocOverloadTag(node: Node): node is JSDocOverloadTag {
return node.kind === SyntaxKind.JSDocOverloadTag;
}

export function isJSDocDeprecatedTag(node: Node): node is JSDocDeprecatedTag {
return node.kind === SyntaxKind.JSDocDeprecatedTag;
}
Expand Down
29 changes: 24 additions & 5 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ import {
JSDocNonNullableType,
JSDocNullableType,
JSDocOptionalType,
JSDocOverloadTag,
JSDocOverrideTag,
JSDocParameterTag,
JSDocPrivateTag,
Expand Down Expand Up @@ -8784,6 +8785,9 @@ namespace Parser {
case "callback":
tag = parseCallbackTag(start, tagName, margin, indentText);
break;
case "overload":
tag = parseOverloadTag(start, tagName, margin, indentText);
break;
case "see":
tag = parseSeeTag(start, tagName, margin, indentText);
break;
Expand Down Expand Up @@ -9277,10 +9281,7 @@ namespace Parser {
return createNodeArray(parameters || [], pos);
}

function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag {
const fullName = parseJSDocTypeNameWithNamespace();
skipWhitespace();
let comment = parseTagComments(indent);
function parseJSDocSignature(start: number, indent: number): JSDocSignature {
const parameters = parseCallbackTagParameters(indent);
const returnTag = tryParse(() => {
if (parseOptionalJsdoc(SyntaxKind.AtToken)) {
Expand All @@ -9290,14 +9291,32 @@ namespace Parser {
}
}
});
const typeExpression = finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start);
return finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start);
}

function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag {
const fullName = parseJSDocTypeNameWithNamespace();
skipWhitespace();
let comment = parseTagComments(indent);
const typeExpression = parseJSDocSignature(start, indent);
if (!comment) {
comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);
}
const end = comment !== undefined ? getNodePos() : typeExpression.end;
return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start, end);
}

function parseOverloadTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocOverloadTag {
skipWhitespace();
let comment = parseTagComments(indent);
const typeExpression = parseJSDocSignature(start, indent);
if (!comment) {
comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);
}
const end = comment !== undefined ? getNodePos() : typeExpression.end;
return finishNode(factory.createJSDocOverloadTag(tagName, typeExpression, comment), start, end);
}

function escapedTextsEqual(a: EntityName, b: EntityName): boolean {
while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) {
if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) {
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ export const enum SyntaxKind {
JSDocReadonlyTag,
JSDocOverrideTag,
JSDocCallbackTag,
JSDocOverloadTag,
JSDocEnumTag,
JSDocParameterTag,
JSDocReturnTag,
Expand Down Expand Up @@ -3829,6 +3830,13 @@ export interface JSDocCallbackTag extends JSDocTag, NamedDeclaration {
readonly typeExpression: JSDocSignature;
}


export interface JSDocOverloadTag extends JSDocTag {
readonly kind: SyntaxKind.JSDocOverloadTag;
readonly parent: JSDoc;
readonly typeExpression: JSDocSignature;
}

export interface JSDocThrowsTag extends JSDocTag {
readonly kind: SyntaxKind.JSDocThrowsTag;
readonly typeExpression?: JSDocTypeExpression;
Expand Down Expand Up @@ -8242,6 +8250,8 @@ export interface NodeFactory {
updateJSDocEnumTag(node: JSDocEnumTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray<JSDocComment> | undefined): JSDocEnumTag;
createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray<JSDocComment>): JSDocCallbackTag;
updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocCallbackTag;
createJSDocOverloadTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, comment?: string | NodeArray<JSDocComment>): JSDocOverloadTag;
updateJSDocOverloadTag(node: JSDocOverloadTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, comment: string | NodeArray<JSDocComment> | undefined): JSDocOverloadTag;
createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocAugmentsTag;
updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | NodeArray<JSDocComment> | undefined): JSDocAugmentsTag;
createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocImplementsTag;
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ import {
isJSDocMemberName,
isJSDocNameReference,
isJSDocNode,
isJSDocOverloadTag,
isJSDocParameterTag,
isJSDocPropertyLikeTag,
isJSDocSignature,
Expand Down Expand Up @@ -5645,7 +5646,7 @@ export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParam

/** template tags are only available when a typedef isn't already using them */
function isNonTypeAliasTemplate(tag: JSDocTag): tag is JSDocTemplateTag {
return isJSDocTemplateTag(tag) && !(tag.parent.kind === SyntaxKind.JSDoc && tag.parent.tags!.some(isJSDocTypeAlias));
return isJSDocTemplateTag(tag) && !(tag.parent.kind === SyntaxKind.JSDoc && (tag.parent.tags!.some(isJSDocTypeAlias) || tag.parent.tags!.some(isJSDocOverloadTag)));
}

/**
Expand Down
9 changes: 9 additions & 0 deletions src/compiler/utilitiesPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ import {
isJSDocEnumTag,
isJSDocFunctionType,
isJSDocImplementsTag,
isJSDocOverloadTag,
isJSDocOverrideTag,
isJSDocParameterTag,
isJSDocPrivateTag,
Expand Down Expand Up @@ -1207,6 +1208,14 @@ function formatJSDocLink(link: JSDocLink | JSDocLinkCode | JSDocLinkPlain) {
*/
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[] {
if (isJSDocSignature(node)) {
if (isJSDoc(node.parent)) {
const overloadTag = find(node.parent.tags, (tag) => {
return isJSDocOverloadTag(tag) && tag.typeExpression === node;
});
if (overloadTag) {
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined);
}
}
return emptyArray;
}
if (isJSDocTypeAlias(node)) {
Expand Down
49 changes: 29 additions & 20 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4338,24 +4338,25 @@ declare namespace ts {
JSDocReadonlyTag = 339,
JSDocOverrideTag = 340,
JSDocCallbackTag = 341,
JSDocEnumTag = 342,
JSDocParameterTag = 343,
JSDocReturnTag = 344,
JSDocThisTag = 345,
JSDocTypeTag = 346,
JSDocTemplateTag = 347,
JSDocTypedefTag = 348,
JSDocSeeTag = 349,
JSDocPropertyTag = 350,
JSDocThrowsTag = 351,
SyntaxList = 352,
NotEmittedStatement = 353,
PartiallyEmittedExpression = 354,
CommaListExpression = 355,
MergeDeclarationMarker = 356,
EndOfDeclarationMarker = 357,
SyntheticReferenceExpression = 358,
Count = 359,
JSDocOverloadTag = 342,
JSDocEnumTag = 343,
JSDocParameterTag = 344,
JSDocReturnTag = 345,
JSDocThisTag = 346,
JSDocTypeTag = 347,
JSDocTemplateTag = 348,
JSDocTypedefTag = 349,
JSDocSeeTag = 350,
JSDocPropertyTag = 351,
JSDocThrowsTag = 352,
SyntaxList = 353,
NotEmittedStatement = 354,
PartiallyEmittedExpression = 355,
CommaListExpression = 356,
MergeDeclarationMarker = 357,
EndOfDeclarationMarker = 358,
SyntheticReferenceExpression = 359,
Count = 360,
FirstAssignment = 63,
LastAssignment = 78,
FirstCompoundAssignment = 64,
Expand Down Expand Up @@ -4384,9 +4385,9 @@ declare namespace ts {
LastStatement = 256,
FirstNode = 163,
FirstJSDocNode = 312,
LastJSDocNode = 351,
LastJSDocNode = 352,
FirstJSDocTagNode = 330,
LastJSDocTagNode = 351
LastJSDocTagNode = 352
}
type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia;
type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral;
Expand Down Expand Up @@ -5939,6 +5940,11 @@ declare namespace ts {
readonly name?: Identifier;
readonly typeExpression: JSDocSignature;
}
interface JSDocOverloadTag extends JSDocTag {
readonly kind: SyntaxKind.JSDocOverloadTag;
readonly parent: JSDoc;
readonly typeExpression: JSDocSignature;
}
interface JSDocThrowsTag extends JSDocTag {
readonly kind: SyntaxKind.JSDocThrowsTag;
readonly typeExpression?: JSDocTypeExpression;
Expand Down Expand Up @@ -7782,6 +7788,8 @@ declare namespace ts {
updateJSDocEnumTag(node: JSDocEnumTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray<JSDocComment> | undefined): JSDocEnumTag;
createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray<JSDocComment>): JSDocCallbackTag;
updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocCallbackTag;
createJSDocOverloadTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, comment?: string | NodeArray<JSDocComment>): JSDocOverloadTag;
updateJSDocOverloadTag(node: JSDocOverloadTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, comment: string | NodeArray<JSDocComment> | undefined): JSDocOverloadTag;
createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocAugmentsTag;
updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | NodeArray<JSDocComment> | undefined): JSDocAugmentsTag;
createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocImplementsTag;
Expand Down Expand Up @@ -9036,6 +9044,7 @@ declare namespace ts {
function isJSDocProtectedTag(node: Node): node is JSDocProtectedTag;
function isJSDocReadonlyTag(node: Node): node is JSDocReadonlyTag;
function isJSDocOverrideTag(node: Node): node is JSDocOverrideTag;
function isJSDocOverloadTag(node: Node): node is JSDocOverloadTag;
function isJSDocDeprecatedTag(node: Node): node is JSDocDeprecatedTag;
function isJSDocSeeTag(node: Node): node is JSDocSeeTag;
function isJSDocEnumTag(node: Node): node is JSDocEnumTag;
Expand Down
Loading