8000 feat(51086): satisfies support in JSDoc by a-tarasyuk · Pull Request #51753 · microsoft/TypeScript · GitHub
[go: up one dir, main page]

Skip to content

feat(51086): satisfies support in JSDoc #51753

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 26 commits into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
59b288f
feat(51086): add satisfies jsdoc tag
a-tarasyuk Dec 2, 2022
dbfcd01
Merge branch 'main' of https://github.com/microsoft/TypeScript into f…
a-tarasyuk Dec 13, 2022
566fb91
Merge branch 'main' of https://github.com/microsoft/TypeScript into f…
a-tarasyuk Dec 13, 2022
659c141
Merge branch 'main' of https://github.com/microsoft/TypeScript into f…
a-tarasyuk Dec 14, 2022
7d823ae
Merge branch 'main' of https://github.com/microsoft/TypeScript into f…
a-tarasyuk Dec 14, 2022
b57066f
Merge branch 'main' of https://github.com/microsoft/TypeScript into f…
a-tarasyuk Dec 16, 2022
14bb0d6
add tests
a-tarasyuk Dec 17, 2022
6e2627f
handle JSDocSatisfies tag on declaration positions with initializer e…
a-tarasyuk Dec 17, 2022
b25fc68
Merge branch 'main' of https://github.com/microsoft/TypeScript into f…
a-tarasyuk Jan 6, 2023
6020674
forbid omitted braces
a-tarasyuk Jan 10, 2023
3c70107
wrap JavaScript checks into a single condition
a-tarasyuk Jan 10, 2023
70edb6d
add tests
a-tarasyuk Jan 10, 2023
c929c19
Merge branch 'main' of https://github.com/microsoft/TypeScript into f…
a-tarasyuk Jan 10, 2023
33ee5d1
Merge branch 'main' of https://github.com/microsoft/TypeScript into f…
a-tarasyuk Jan 10, 2023
b9205de
fix tests
a-tarasyuk Jan 10, 2023
398e119
fix typo
a-tarasyuk Jan 11, 2023
fe1ee79
Merge branch 'main' of https://github.com/microsoft/TypeScript into f…
a-tarasyuk Jan 11, 2023
62b9c22
improve handling of duplicate tags. fix handling a parenthesized init…
a-tarasyuk Jan 12, 2023
e07c71e
Merge branch 'main' of https://github.com/microsoft/TypeScript into f…
a-tarasyuk Jan 13, 2023
98f7db6
update test
a-tarasyuk Jan 13, 2023
6b43a92
add satisfies tag completions
a-tarasyuk Jan 14, 2023
ffb310d
satisfies tag quick info
a-tarasyuk Jan 14, 2023
9fc9292
satisfies tag rename
a-tarasyuk Jan 14, 2023
3ad2a6e
satisfies tag find all references
a-tarasyuk Jan 14, 2023
c90c148
goto definition on satisfies tag
a-tarasyuk Jan 14, 2023
a9e7fda
add jsDoc parsing satisfies tag tests
a-tarasyuk Jan 14, 2023
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
Next Next commit
feat(51086): add satisfies jsdoc tag
  • Loading branch information
a-tarasyuk committed Dec 5, 2022
commit 59b288f34f8a949d723343cf76a202f74f65e3a5
38 changes: 28 additions & 10 deletions src/compiler/checker.ts
9E81
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ import {
getJSDocHost,
getJSDocParameterTags,
getJSDocRoot,
getJSDocSatisfiesExpressionType,
getJSDocTags,
getJSDocThisTag,
getJSDocType,
Expand Down Expand Up @@ -338,8 +339,8 @@ import {
hasAccessorModifier,
hasAmbientModifier,
hasContextSensitiveParameters,
HasDecorators,
hasDecorators,
HasDecorators,
hasDynamicName,
hasEffectiveModifier,
hasEffectiveModifiers,
Expand All @@ -348,8 +349,8 @@ import {
hasExtension,
HasIllegalDecorators,
HasIllegalModifiers,
HasInitializer,
hasInitializer,
HasInitializer,
hasJSDocNodes,
hasJSDocParameterTags,
hasJsonModuleEmitEnabled,
Expand Down Expand Up @@ -539,6 +540,7 @@ import {
isJSDocParameterTag,
isJSDocPropertyLikeTag,
isJSDocReturnTag,
isJSDocSatisfiesExpression,
isJSDocSignature,
isJSDocTemplateTag,
isJSDocTypeAlias,
Expand Down Expand Up @@ -713,6 +715,7 @@ import {
JSDocPropertyTag,
JSDocProtectedTag,
JSDocPublicTag,
JSDocSatisfiesTag,
JSDocSignature,
JSDocTemplateTag,
JSDocTypedefTag,
Expand Down Expand Up @@ -28682,6 +28685,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression);
return getContextualTypeForSubstitutionExpression(parent.parent as TemplateExpression, node);
case SyntaxKind.ParenthesizedExpression: {
if (isJSDocSatisfiesExpression(parent)) {
return getTypeFromTypeNode(getJSDocSatisfiesExpressionType(parent));
}
// Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast.
const tag = isInJSFile(parent) ? getJSDocTypeTag(parent) : undefined;
return !tag ? getContextualType(parent as ParenthesizedExpression, contextFlags) :
Expand Down Expand Up @@ -33674,15 +33680,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

function checkSatisfiesExpression(node: SatisfiesExpression) {
checkSourceElement(node.type);
const exprType = checkExpression(node.expression);
return checkSatisfiesExpressionWorker(node.expression, node.type);
}

const targetType = getTypeFromTypeNode(node.type);
function checkSatisfiesExpressionWorker(expression: Expression, target: TypeNode, checkMode?: CheckMode) {
const exprType = checkExpression(expression, checkMode);
const targetType = getTypeFromTypeNode(target);
if (isErrorType(targetType)) {
return targetType;
}

checkTypeAssignableToAndOptionallyElaborate(exprType, targetType, node.type, node.expression, Diagnostics.Type_0_does_not_satisfy_the_expected_type_1);

checkTypeAssignableToAndOptionallyElaborate(exprType, targetType, target, expression, Diagnostics.Type_0_does_not_satisfy_the_expected_type_1);
return exprType;
}

Expand Down Expand Up @@ -36406,9 +36413,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type {
if (hasJSDocNodes(node) && isJSDocTypeAssertion(node)) {
const type = getJSDocTypeAssertionType(node);
return checkAssertionWorker(type, type, node.expression, checkMode);
if (hasJSDocNodes(node)) {
if (isJSDocSatisfiesExpression(node)) {
return checkSatisfiesExpressionWorker(node.expression, getJSDocSatisfiesExpressionType(node), checkMode);
}
if (isJSDocTypeAssertion(node)) {
const type = getJSDocTypeAssertionType(node);
return checkAssertionWorker(type, type, node.expression, checkMode);
}
}
return checkExpression(node.expression, checkMode);
}
Expand Down Expand Up @@ -38632,6 +38644,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
checkSourceElement(node.typeExpression);
}

function checkJSDocSatisfiesTag(node: JSDocSatisfiesTag) {
checkSourceElement(node.typeExpression);
}

function checkJSDocLinkLikeTag(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain) {
if (node.name) {
resolveJSDocMemberName(node.name, /*ignoreErrors*/ true);
Expand Down Expand Up @@ -43138,6 +43154,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
case SyntaxKind.JSDocProtectedTag:
case SyntaxKind.JSDocPrivateTag:
return checkJSDocAccessibilityModifiers(node as JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag);
case SyntaxKind.JSDocSatisfiesTag:
return checkJSDocSatisfiesTag(node as JSDocSatisfiesTag);
case SyntaxKind.IndexedAccessType:
return checkIndexedAccessType(node as IndexedAccessTypeNode);
case SyntaxKind.MappedType:
Expand Down
6 changes: 4 additions & 2 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ import {
JSDocOptionalType,
JSDocPropertyLikeTag,
JSDocReturnTag,
JSDocSatisfiesTag,
JSDocSeeTag,
JSDocSignature,
JSDocTag,
Expand Down Expand Up @@ -2122,7 +2123,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
case SyntaxKind.JSDocReturnTag:
case SyntaxKind.JSDocThisTag:
case SyntaxKind.JSDocTypeTag:
return emitJSDocSimpleTypedTag(node as JSDocTypeTag);
case SyntaxKind.JSDocSatisfiesTag:
return emitJSDocSimpleTypedTag(node as JSDocTypeTag | JSDocReturnTag | JSDocThisTag | JSDocTypeTag | JSDocSatisfiesTag);
case SyntaxKind.JSDocTemplateTag:
return emitJSDocTemplateTag(node as JSDocTemplateTag);
case SyntaxKind.JSDocTypedefTag:
Expand Down Expand Up @@ -4299,7 +4301,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
write("*/");
}

function emitJSDocSimpleTypedTag(tag: JSDocTypeTag | JSDocThisTag | JSDocEnumTag | JSDocReturnTag) {
function emitJSDocSimpleTypedTag(tag: JSDocTypeTag | JSDocThisTag | JSDocEnumTag | JSDocReturnTag | JSDocSatisfiesTag) {
emitJSDocTagName(tag.tagName);
emitJSDocTypeExpression(tag.typeExpression);
emitJSDocComment(tag.comment);
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/factory/nodeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ import {
JSDocPublicTag,
JSDocReadonlyTag,
JSDocReturnTag,
JSDocSatisfiesTag,
JSDocSeeTag,
JSDocSignature,
JSDocTag,
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>(Synt 10000 axKind.JSDocDeprecatedTag); },
get updateJSDocDeprecatedTag() { return getJSDocSimpleTagUpdateFunction<JSDocDeprecatedTag>(SyntaxKind.JSDocDeprecatedTag); },
get createJSDocSatisfiesTag() { return getJSDocTypeLikeTagCreateFunction<JSDocSatisfiesTag>(SyntaxKind.JSDocSatisfiesTag); },
get updateJSDocSatisfiesTag() { return getJSDocTypeLikeTagUpdateFunction<JSDocSatisfiesTag>(SyntaxKind.JSDocSatisfiesTag); },
createJSDocUnknownTag,
updateJSDocUnknownTag,
createJSDocText,
Expand Down Expand Up @@ -5317,6 +5320,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
// createJSDocReturnTag
// createJSDocThisTag
// createJSDocEnumTag
// createJSDocSatisfiesTag
function createJSDocTypeLikeTagWorker<T extends JSDocTag & { typeExpression?: JSDocTypeExpression }>(kind: T["kind"], tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string | NodeArray<JSDocComment>) {
const node = createBaseJSDocTag<T>(kind, tagName ?? createIdentifier(getDefaultTagNameForKind(kind)), comment);
node.typeExpression = typeExpression;
Expand All @@ -5328,6 +5332,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
// updateJSDocReturnTag
// updateJSDocThisTag
// updateJSDocEnumTag
// updateJSDocSatisfiesTag
function updateJSDocTypeLikeTagWorker<T extends JSDocTag & { typeExpression?: JSDocTypeExpression }>(kind: T["kind"], node: T, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocTypeExpression | undefined, comment: string | NodeArray<JSDocComment> | undefined) {
return node.tagName !== tagName
|| node.typeExpression !== typeExpression
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 @@ -105,6 +105,7 @@ import {
JSDocPublicTag,
JSDocReadonlyTag,
JSDocReturnTag,
JSDocSatisfiesTag,
JSDocSeeTag,
JSDocSignature,
JSDocTemplateTag,
Expand Down Expand Up @@ -1176,6 +1177,10 @@ export function isJSDocImplementsTag(node: Node): node is JSDocImplementsTag {
return node.kind === SyntaxKind.JSDocImplementsTag;
}

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

// Synthesized list

/** @internal */
Expand Down
27 changes: 22 additions & 5 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ import {
isJSDocFunctionType,
isJSDocNullableType,
isJSDocReturnTag,
isJSDocSatisfiesTag,
isJSDocTypeTag,
isJsxOpeningElement,
isJsxOpeningFragment,
Expand Down Expand Up @@ -189,6 +190,7 @@ import {
JSDocPublicTag,
JSDocReadonlyTag,
JSDocReturnTag,
JSDocSatisfiesTag,
JSDocSeeTag,
JSDocSignature,
JSDocSyntaxKind,
Expand Down Expand Up @@ -1100,10 +1102,12 @@ 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.JSDocSatisfiesTag]: 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 +1201,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 | JSDocSatisfiesTag, 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 @@ -8782,6 +8786,9 @@ namespace Parser {
case "callback":
tag = parseCallbackTag(start, tagName, margin, indentText);
break;
case "satisfies":
tag = parseSatisfiesTag(start, tagName, margin, indentText);
break;
case "see":
tag = parseSeeTag(start, tagName, margin, indentText);
break;
Expand Down Expand Up @@ -9137,6 +9144,16 @@ namespace Parser {
return finishNode(factory.createJSDocAugmentsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
}

function parseSatisfiesTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocSatisfiesTag {
if (some(tags, isJSDocSatisfiesTag)) {
parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
}

const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
const comments = margin !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), margin, indentText) : undefined;
return finishNode(factory.createJSDocSatisfiesTag(tagName, typeExpression, comments), start);
}

function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression } {
const usedBrace = parseOptional(SyntaxKind.OpenBraceToken);
const pos = getNodePos();
Expand Down
14 changes: 14 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ export const enum SyntaxKind {
JSDocTypedefTag,
JSDocSeeTag,
JSDocPropertyTag,
JSDocSatisfiesTag,

// Synthesized list
SyntaxList,
Expand Down Expand Up @@ -954,6 +955,7 @@ export type ForEachChildNodes =
| JSDocReadonlyTag
| JSDocDeprecatedTag
| JSDocOverrideTag
| JSDocSatisfiesTag
;

/** @internal */
Expand Down Expand Up @@ -3857,6 +3859,16 @@ export interface JSDocTypeLiteral extends JSDocType {
readonly isArrayType: boolean;
}

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

/** @internal */
export interface JSDocSatisfiesExpression extends ParenthesizedExpression {
readonly _jsDocSatisfiesExpressionBrand: never;
}

// NOTE: Ensure this is up-to-date with src/debug/debug.ts
export const enum FlowFlags {
Unreachable = 1 << 0, // Unreachable code
Expand Down Expand Up @@ -8237,6 +8249,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;
createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray<JSDocComment>): JSDocSatisfiesTag;
updateJSDocSatisfiesTag(node: JSDocSatisfiesTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray<JSDocComment> | undefined): JSDocSatisfiesTag;
createJSDocText(text: string): JSDocText;
updateJSDocText(node: JSDocText, text: string): JSDocText;
createJSDocComment(comment?: string | NodeArray<JSDocComment> | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc;
Expand Down
17 changes: 16 additions & 1 deletion src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ import {
getJSDocPublicTagNoCache,
getJSDocReadonlyTagNoCache,
getJSDocReturnType,
getJSDocSatisfiesTag,
getJSDocTags,
getJSDocType,
getJSDocTypeParameterTags,
Expand All @@ -193,8 +194,8 @@ import {
getTrailingCommentRanges,
HasExpressionInitializer,
hasExtension,
HasInitializer,
hasInitializer,
HasInitializer,
HasJSDoc,
hasJSDocNodes,
HasModifiers,
Expand Down Expand Up @@ -330,6 +331,7 @@ import {
JSDocMemberName,
JSDocParameterTag,
JSDocPropertyLikeTag,
JSDocSatisfiesExpression,
JSDocSignature,
JSDocTag,
JSDocTemplateTag,
Expand Down Expand Up @@ -9128,3 +9130,16 @@ export function canUsePropertyAccess(name: string, languageVersion: ScriptTarget
export function hasTabstop(node: Node): boolean {
return getSnippetElement(node)?.kind === SnippetKind.TabStop;
}

/** @internal */
export function isJSDocSatisfiesExpression(node: Node): node is JSDocSatisfiesExpression {
return isInJSFile(node) && isParenthesizedExpression(node) && !!getJSDocSatisfiesTag(node);
}

/** @internal */
export function getJSDocSatisfiesExpressionType(node: JSDocSatisfiesExpression) {
const tag = getJSDocSatisfiesTag(node);
const type = tag && tag.typeExpression && tag.typeExpression.type;
Debug.assertIsDefined(type);
return type;
}
8 changes: 7 additions & 1 deletion src/compiler/utilitiesPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ import {
getJSDocCommentsAndTags,
getJSDocTypeParameterDeclarations,
hasAccessorModifier,
hasDecorators,
HasDecorators,
hasDecorators,
HasExpressionInitializer,
HasInitializer,
HasJSDoc,
Expand Down Expand Up @@ -129,6 +129,7 @@ import {
isJSDocPublicTag,
isJSDocReadonlyTag,
isJSDocReturnTag,
isJSDocSatisfiesTag,
isJSDocSignature,
isJSDocTemplateTag,
isJSDocThisTag,
Expand Down Expand Up @@ -175,6 +176,7 @@ import {
JSDocPublicTag,
JSDocReadonlyTag,
JSDocReturnTag,
JSDocSatisfiesTag,
JSDocSignature,
JSDocTag,
JSDocTemplateTag,
Expand Down Expand Up @@ -1087,6 +1089,10 @@ export function getJSDocTemplateTag(node: Node): JSDocTemplateTag | undefined {
return getFirstJSDocTag(node, isJSDocTemplateTag);
}

export function getJSDocSatisfiesTag(node: Node): JSDocSatisfiesTag | undefined {
return getFirstJSDocTag(node, isJSDocSatisfiesTag);
}

/** Gets the JSDoc type tag for the node if present and valid */
export function getJSDocTypeTag(node: Node): JSDocTypeTag | undefined {
// We should have already issued an error if there were multiple type jsdocs, so just use the first one.
Expand Down
Loading
0