Skip to content
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
1 change: 1 addition & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2122,6 +2122,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
case SyntaxKind.JSDocReturnTag:
case SyntaxKind.JSDocThisTag:
case SyntaxKind.JSDocTypeTag:
case SyntaxKind.JSDocThrowsTag:
return emitJSDocSimpleTypedTag(node as JSDocTypeTag);
case SyntaxKind.JSDocTemplateTag:
return emitJSDocTemplateTag(node as JSDocTemplateTag);
Expand Down
3 changes: 3 additions & 0 deletions src/compiler/factory/nodeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ import {
JSDocTemplateTag,
JSDocText,
JSDocThisTag,
JSDocThrowsTag,
JSDocType,
JSDocTypedefTag,
JSDocTypeExpression,
Expand Down Expand Up @@ -871,6 +872,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
get updateJSDocOverrideTag() { return getJSDocSimpleTagUpdateFunction<JSDocOverrideTag>(SyntaxKind.JSDocOverrideTag); },
get createJSDocDeprecatedTag() { return getJSDocSimpleTagCreateFunction<JSDocDeprecatedTag>(SyntaxKind.JSDocDeprecatedTag); },
get updateJSDocDeprecatedTag() { return getJSDocSimpleTagUpdateFunction<JSDocDeprecatedTag>(SyntaxKind.JSDocDeprecatedTag); },
get createJSDocThrowsTag() { return getJSDocTypeLikeTagCreateFunction<JSDocThrowsTag>(SyntaxKind.JSDocThrowsTag); },
get updateJSDocThrowsTag() { return getJSDocTypeLikeTagUpdateFunction<JSDocThrowsTag>(SyntaxKind.JSDocThrowsTag); },
createJSDocUnknownTag,
updateJSDocUnknownTag,
createJSDocText,
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 @@ -109,6 +109,7 @@ import {
JSDocSignature,
JSDocTemplateTag,
JSDocThisTag,
JSDocThrowsTag,
JSDocTypedefTag,
JSDocTypeExpression,
JSDocTypeLiteral,
Expand Down Expand Up @@ -1176,6 +1177,10 @@ export function isJSDocImplementsTag(node: Node): node is JSDocImplementsTag {
return node.kind === SyntaxKind.JSDocImplementsTag;
}

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

// Synthesized list

/** @internal */
Expand Down
22 changes: 17 additions & 5 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ import {
JSDocTemplateTag,
JSDocText,
JSDocThisTag,
JSDocThrowsTag,
JSDocTypedefTag,
JSDocTypeExpression,
JSDocTypeLiteral,
Expand Down Expand Up @@ -1100,10 +1101,11 @@ const forEachChildTable: ForEachChildTable = {
visitNode(cbNode, node.typeExpression) ||
(typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
},
[SyntaxKind.JSDocReturnTag]: forEachChildInJSDocReturnTag,
[SyntaxKind.JSDocTypeTag]: forEachChildInJSDocReturnTag,
[SyntaxKind.JSDocThisTag]: forEachChildInJSDocReturnTag,
[SyntaxKind.JSDocEnumTag]: forEachChildInJSDocReturnTag,
[SyntaxKind.JSDocReturnTag]: forEachChildInJSDocTypeLikeTag,
[SyntaxKind.JSDocTypeTag]: forEachChildInJSDocTypeLikeTag,
[SyntaxKind.JSDocThisTag]: forEachChildInJSDocTypeLikeTag,
[SyntaxKind.JSDocEnumTag]: forEachChildInJSDocTypeLikeTag,
[SyntaxKind.JSDocThrowsTag]: forEachChildInJSDocTypeLikeTag,
[SyntaxKind.JSDocSignature]: function forEachChildInJSDocSignature<T>(node: JSDocSignature, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
return forEach(node.typeParameters, cbNode) ||
forEach(node.parameters, cbNode) ||
Expand Down Expand Up @@ -1197,7 +1199,7 @@ function forEachChildInJSDocParameterOrPropertyTag<T>(node: JSDocParameterTag |
(typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
}

function forEachChildInJSDocReturnTag<T>(node: JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
function forEachChildInJSDocTypeLikeTag<T>(node: JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag | JSDocThrowsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
return visitNode(cbNode, node.tagName) ||
visitNode(cbNode, node.typeExpression) ||
(typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
Expand Down Expand Up @@ -8785,6 +8787,10 @@ namespace Parser {
case "see":
tag = parseSeeTag(start, tagName, margin, indentText);
break;
case "exception":
case "throws":
tag = parseThrowsTag(start, tagName, margin, indentText);
break;
default:
tag = parseUnknownTag(start, tagName, margin, indentText);
break;
Expand Down Expand Up @@ -9090,6 +9096,12 @@ namespace Parser {
return finishNode(factory.createJSDocSeeTag(tagName, nameExpression, comments), start);
}

function parseThrowsTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocThrowsTag {
const typeExpression = tryParseTypeExpression();
const comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);
return finishNode(factory.createJSDocThrowsTag(tagName, typeExpression, comment), start);
}

function parseAuthorTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocAuthorTag {
const commentStart = getNodePos();
const textOnly = parseAuthorNameAndEmail();
Expand Down
13 changes: 11 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ export const enum SyntaxKind {
JSDocTypedefTag,
JSDocSeeTag,
JSDocPropertyTag,
JSDocThrowsTag,

// Synthesized list
SyntaxList,
Expand Down Expand Up @@ -473,9 +474,9 @@ export const enum SyntaxKind {
LastStatement = DebuggerStatement,
FirstNode = QualifiedName,
FirstJSDocNode = JSDocTypeExpression,
LastJSDocNode = JSDocPropertyTag,
LastJSDocNode = JSDocThrowsTag,
FirstJSDocTagNode = JSDocTag,
LastJSDocTagNode = JSDocPropertyTag,
LastJSDocTagNode = JSDocThrowsTag,
/** @internal */ FirstContextualKeyword = AbstractKeyword,
/** @internal */ LastContextualKeyword = OfKeyword,
}
Expand Down Expand Up @@ -952,6 +953,7 @@ export type ForEachChildNodes =
| JSDocProtectedTag
| JSDocReadonlyTag
| JSDocDeprecatedTag
| JSDocThrowsTag
| JSDocOverrideTag
;

Expand Down Expand Up @@ -3825,6 +3827,11 @@ export interface JSDocCallbackTag extends JSDocTag, NamedDeclaration {
readonly typeExpression: JSDocSignature;
}

export interface JSDocThrowsTag extends JSDocTag {
readonly kind: SyntaxKind.JSDocThrowsTag;
readonly typeExpression?: JSDocTypeExpression;
}

export interface JSDocSignature extends JSDocType, Declaration {
readonly kind: SyntaxKind.JSDocSignature;
readonly typeParameters?: readonly JSDocTemplateTag[];
Expand Down Expand Up @@ -8235,6 +8242,8 @@ export interface NodeFactory {
updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier, comment?: string | NodeArray<JSDocComment>): JSDocDeprecatedTag;
createJSDocOverrideTag(tagName: Identifier, comment?: string | NodeArray<JSDocComment>): JSDocOverrideTag;
updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier, comment?: string | NodeArray<JSDocComment>): JSDocOverrideTag;
createJSDocThrowsTag(tagName: Identifier, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray<JSDocComment>): JSDocThrowsTag;
updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray<JSDocComment> | undefined): JSDocThrowsTag;
createJSDocText(text: string): JSDocText;
updateJSDocText(node: JSDocText, text: string): JSDocText;
createJSDocComment(comment?: string | NodeArray<JSDocComment> | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc;
Expand Down
6 changes: 6 additions & 0 deletions src/services/classifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
JSDocSeeTag,
JSDocTemplateTag,
JSDocThisTag,
JSDocThrowsTag,
JSDocTypedefTag,
JSDocTypeTag,
JsxAttribute,
Expand Down Expand Up @@ -847,6 +848,11 @@ export function getEncodedSyntacticClassifications(cancellationToken: Cancellati
case SyntaxKind.JSDocImplementsTag:
commentStart = (tag as JSDocImplementsTag | JSDocAugmentsTag).class.end;
break;
case SyntaxKind.JSDocThrowsTag:
processElement((tag as JSDocThrowsTag).typeExpression);
pos = tag.end;
commentStart = (tag as JSDocThrowsTag).typeExpression?.end || commentStart;
break;
}
if (typeof tag.comment === "object") {
pushCommentRange(tag.comment.pos, tag.comment.end - tag.comment.pos);
Expand Down
11 changes: 10 additions & 1 deletion src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ import {
JSDocTag,
JSDocTagInfo,
JSDocTemplateTag,
JSDocThrowsTag,
JSDocTypedefTag,
JSDocTypeExpression,
JSDocTypeTag,
Expand Down Expand Up @@ -2612,7 +2613,14 @@ function getCompletionData(
flags,
};

type JSDocTagWithTypeExpression = JSDocParameterTag | JSDocPropertyTag | JSDocReturnTag | JSDocTypeTag | JSDocTypedefTag | JSDocTemplateTag;
type JSDocTagWithTypeExpression =
| JSDocParameterTag
| JSDocPropertyTag
| JSDocReturnTag
| JSDocTypeTag
| JSDocTypedefTag
| JSDocTemplateTag
| JSDocThrowsTag;

function isTagWithTypeExpression(tag: JSDocTag): tag is JSDocTagWithTypeExpression {
switch (tag.kind) {
Expand All @@ -2621,6 +2629,7 @@ function getCompletionData(
case SyntaxKind.JSDocReturnTag:
case SyntaxKind.JSDocTypeTag:
case SyntaxKind.JSDocTypedefTag:
case SyntaxKind.JSDocThrowsTag:
return true;
case SyntaxKind.JSDocTemplateTag:
return !!(tag as JSDocTemplateTag).constraint;
Expand Down
5 changes: 5 additions & 0 deletions src/services/jsDoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import {
JSDocTag,
JSDocTagInfo,
JSDocTemplateTag,
JSDocThrowsTag,
JSDocTypedefTag,
JSDocTypeTag,
lastOrUndefined,
Expand Down Expand Up @@ -258,6 +259,10 @@ function getCommentDisplayParts(tag: JSDocTag, checker?: TypeChecker): SymbolDis
const { comment, kind } = tag;
const namePart = getTagNameDisplayPart(kind);
switch (kind) {
case SyntaxKind.JSDocThrowsTag:
const typeExpression = (tag as JSDocThrowsTag).typeExpression;
return typeExpression ? withNode(typeExpression) :
comment === undefined ? undefined : getDisplayPartsFromComment(comment, checker);
case SyntaxKind.JSDocImplementsTag:
return withNode((tag as JSDocImplementsTag).class);
case SyntaxKind.JSDocAugmentsTag:
Expand Down
29 changes: 29 additions & 0 deletions src/testRunner/unittests/jsDocParsing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,35 @@ describe("unittests:: JSDocParsing", () => {
parsesCorrectly("paramWithoutType",
`/**
* @param foo
*/`);
parsesCorrectly("throwsTag1",
`/**
* @throws {Error}
*/`);

parsesCorrectly("throwsTag2",
`/**
* @throws free-form description
*/`);

parsesCorrectly("throwsTag3",
`/**
* @throws {Error} description
*/`);

parsesCorrectly("exceptionTag1",
`/**
* @exception {Error}
*/`);

parsesCorrectly("exceptionTag2",
`/**
* @exception free-form description
*/`);

parsesCorrectly("exceptionTag3",
`/**
* @exception {Error} description
*/`);
parsesCorrectly("typedefTagWithChildrenTags",
`/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"kind": "JSDoc",
"pos": 0,
"end": 31,
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 0,
"tags": {
"0": {
"kind": "JSDocThrowsTag",
"pos": 8,
"end": 29,
"modifierFlagsCache": 0,
"transformFlags": 0,
"tagName": {
"kind": "Identifier",
"pos": 9,
"end": 18,
"modifierFlagsCache": 0,
"transformFlags": 0,
"escapedText": "exception"
},
"typeExpression": {
"kind": "JSDocTypeExpression",
"pos": 19,
"end": 26,
"modifierFlagsCache": 0,
"transformFlags": 0,
"type": {
"kind": "TypeReference",
"pos": 20,
"end": 25,
"modifierFlagsCache": 0,
"transformFlags": 1,
"typeName": {
"kind": "Identifier",
"pos": 20,
"end": 25,
"modifierFlagsCache": 0,
"transformFlags": 0,
"escapedText": "Error"
}
}
}
},
"length": 1,
"pos": 8,
"end": 29,
"hasTrailingComma": false,
"transformFlags": 0
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"kind": "JSDoc",
"pos": 0,
"end": 45,
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 0,
"tags": {
"0": {
"kind": "JSDocThrowsTag",
"pos": 8,
"end": 43,
"modifierFlagsCache": 0,
"transformFlags": 0,
"tagName": {
"kind": "Identifier",
"pos": 9,
"end": 18,
"modifierFlagsCache": 0,
"transformFlags": 0,
"escapedText": "exception"
},
"comment": "free-form description"
},
"length": 1,
"pos": 8,
"end": 43,
"hasTrailingComma": false,
"transformFlags": 0
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"kind": "JSDoc",
"pos": 0,
"end": 43,
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 0,
"tags": {
"0": {
"kind": "JSDocThrowsTag",
"pos": 8,
"end": 41,
"modifierFlagsCache": 0,
"transformFlags": 0,
"tagName": {
"kind": "Identifier",
"pos": 9,
"end": 18,
"modifierFlagsCache": 0,
"transformFlags": 0,
"escapedText": "exception"
},
"comment": "description",
"typeExpression": {
"kind": "JSDocTypeExpression",
"pos": 19,
"end": 26,
"modifierFlagsCache": 0,
"transformFlags": 0,
"type": {
"kind": "TypeReference",
"pos": 20,
"end": 25,
"modifierFlagsCache": 0,
"transformFlags": 1,
"typeName": {
"kind": "Identifier",
"pos": 20,
"end": 25,
"modifierFlagsCache": 0,
"transformFlags": 0,
"escapedText": "Error"
}
}
}
},
"length": 1,
"pos": 8,
"end": 41,
"hasTrailingComma": false,
"transformFlags": 0
}
}
Loading