Skip to content

Commit 1f3599d

Browse files
committed
feat(17227): add abstract JSDoc tag
1 parent dfe2342 commit 1f3599d

29 files changed

+610
-60
lines changed

src/compiler/checker.ts

+18-6
Original file line numberDiff line numberDiff line change
@@ -6800,6 +6800,7 @@ namespace ts {
68006800
...!length(baseTypes) ? [] : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))],
68016801
...!length(implementsExpressions) ? [] : [factory.createHeritageClause(SyntaxKind.ImplementsKeyword, implementsExpressions)]
68026802
];
6803+
const modifiers = originalDecl && hasEffectiveModifier(originalDecl, ModifierFlags.Abstract) ? factory.createModifiersFromModifierFlags(ModifierFlags.Abstract) : undefined;
68036804
const symbolProps = getNonInterhitedProperties(classType, baseTypes, getPropertiesOfType(classType));
68046805
const publicSymbolProps = filter(symbolProps, s => {
68056806
// `valueDeclaration` could be undefined if inherited from
@@ -6846,7 +6847,7 @@ namespace ts {
68466847
context.enclosingDeclaration = oldEnclosing;
68476848
addResult(setTextRange(factory.createClassDeclaration(
68486849
/*decorators*/ undefined,
6849-
/*modifiers*/ undefined,
6850+
modifiers,
68506851
localName,
68516852
typeParamDecls,
68526853
heritageClauses,
@@ -28036,7 +28037,7 @@ namespace ts {
2803628037
// In the case of a merged class-module or class-interface declaration,
2803728038
// only the class declaration node will have the Abstract flag set.
2803828039
const valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol);
28039-
if (valueDecl && hasSyntacticModifier(valueDecl, ModifierFlags.Abstract)) {
28040+
if (valueDecl && hasEffectiveModifier(valueDecl, ModifierFlags.Abstract)) {
2804028041
error(node, Diagnostics.Cannot_create_an_instance_of_an_abstract_class);
2804128042
return resolveErrorCall(node);
2804228043
}
@@ -29531,7 +29532,7 @@ namespace ts {
2953129532
if (type && type.flags & TypeFlags.Never) {
2953229533
error(getEffectiveReturnTypeNode(func), Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point);
2953329534
}
29534-
else if (type && !hasExplicitReturn) {
29535+
else if (type && !hasExplicitReturn && !hasEffectiveModifier(func, ModifierFlags.Abstract)) {
2953529536
// minimal check: function has syntactic return type annotation and no explicit return statements in the body
2953629537
// this function does not conform to the specification.
2953729538
// NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present
@@ -31899,7 +31900,7 @@ namespace ts {
3189931900

3190031901
// Abstract methods cannot have an implementation.
3190131902
// Extra checks are to avoid reporting multiple errors relating to the "abstractness" of the node.
31902-
if (hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration && node.body) {
31903+
if (hasEffectiveModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration && node.body && !isInJSFile(node)) {
3190331904
error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name));
3190431905
}
3190531906
}
@@ -31996,7 +31997,7 @@ namespace ts {
3199631997
checkSignatureDeclaration(node);
3199731998
if (node.kind === SyntaxKind.GetAccessor) {
3199831999
if (!(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) {
31999-
if (!(node.flags & NodeFlags.HasExplicitReturn)) {
32000+
if (!(node.flags & NodeFlags.HasExplicitReturn) && !(isInJSFile(node) && hasEffectiveModifier(node, ModifierFlags.Abstract))) {
3200032001
error(node.name, Diagnostics.A_get_accessor_must_return_a_value);
3200132002
}
3200232003
}
@@ -33277,6 +33278,15 @@ namespace ts {
3327733278
checkSignatureDeclaration(node);
3327833279
}
3327933280

33281+
function checkJSDocAbstractTag(node: JSDocAbstractTag): void {
33282+
const host = getEffectiveJSDocHost(node);
33283+
if (host && isClassElement(host)) {
33284+
if (!hasEffectiveModifier(host.parent, ModifierFlags.Abstract)) {
33285+
error(host, Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class);
33286+
}
33287+
}
33288+
}
33289+
3328033290
function checkJSDocImplementsTag(node: JSDocImplementsTag): void {
3328133291
const classLike = getEffectiveJSDocHost(node);
3328233292
if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) {
@@ -36969,6 +36979,8 @@ namespace ts {
3696936979
return checkImportType(<ImportTypeNode>node);
3697036980
case SyntaxKind.NamedTupleMember:
3697136981
return checkNamedTupleMember(<NamedTupleMember>node);
36982+
case SyntaxKind.JSDocAbstractTag:
36983+
return checkJSDocAbstractTag(<JSDocAbstractTag>node);
3697236984
case SyntaxKind.JSDocAugmentsTag:
3697336985
return checkJSDocAugmentsTag(node as JSDocAugmentsTag);
3697436986
case SyntaxKind.JSDocImplementsTag:
@@ -39851,7 +39863,7 @@ namespace ts {
3985139863
return grammarErrorAtPos(accessor, accessor.end - 1, ";".length, Diagnostics._0_expected, "{");
3985239864
}
3985339865
}
39854-
if (accessor.body && hasSyntacticModifier(accessor, ModifierFlags.Abstract)) {
39866+
if (accessor.body && hasSyntacticModifier(accessor, ModifierFlags.Abstract) && !isInJSFile(accessor)) {
3985539867
return grammarErrorOnNode(accessor, Diagnostics.An_abstract_accessor_cannot_have_an_implementation);
3985639868
}
3985739869
if (accessor.typeParameters) {

src/compiler/factory/nodeFactory.ts

+3
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ namespace ts {
354354
get updateJSDocThisTag() { return getJSDocTypeLikeTagUpdateFunction<JSDocThisTag>(SyntaxKind.JSDocThisTag); },
355355
get createJSDocEnumTag() { return getJSDocTypeLikeTagCreateFunction<JSDocEnumTag>(SyntaxKind.JSDocEnumTag); },
356356
get updateJSDocEnumTag() { return getJSDocTypeLikeTagUpdateFunction<JSDocEnumTag>(SyntaxKind.JSDocEnumTag); },
357+
get createJSDocAbstractTag() { return getJSDocSimpleTagCreateFunction<JSDocAbstractTag>(SyntaxKind.JSDocAbstractTag); },
358+
get updateJSDocAbstractTag() { return getJSDocSimpleTagUpdateFunction<JSDocAbstractTag>(SyntaxKind.JSDocAbstractTag); },
357359
get createJSDocAuthorTag() { return getJSDocSimpleTagCreateFunction<JSDocAuthorTag>(SyntaxKind.JSDocAuthorTag); },
358360
get updateJSDocAuthorTag() { return getJSDocSimpleTagUpdateFunction<JSDocAuthorTag>(SyntaxKind.JSDocAuthorTag); },
359361
get createJSDocClassTag() { return getJSDocSimpleTagCreateFunction<JSDocClassTag>(SyntaxKind.JSDocClassTag); },
@@ -5859,6 +5861,7 @@ namespace ts {
58595861
case SyntaxKind.JSDocReturnTag: return "returns";
58605862
case SyntaxKind.JSDocThisTag: return "this";
58615863
case SyntaxKind.JSDocEnumTag: return "enum";
5864+
case SyntaxKind.JSDocAbstractTag: return "abstract";
58625865
case SyntaxKind.JSDocAuthorTag: return "author";
58635866
case SyntaxKind.JSDocClassTag: return "class";
58645867
case SyntaxKind.JSDocPublicTag: return "public";

src/compiler/factory/nodeTests.ts

+4
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,10 @@ namespace ts {
757757
return node.kind === SyntaxKind.JSDocAugmentsTag;
758758
}
759759

760+
export function isJSDocAbstractTag(node: Node): node is JSDocAbstractTag {
761+
return node.kind === SyntaxKind.JSDocAbstractTag;
762+
}
763+
760764
export function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag {
761765
return node.kind === SyntaxKind.JSDocAuthorTag;
762766
}

src/compiler/parser.ts

+4
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ namespace ts {
532532
case SyntaxKind.JSDocTypeLiteral:
533533
return forEach((node as JSDocTypeLiteral).jsDocPropertyTags, cbNode);
534534
case SyntaxKind.JSDocTag:
535+
case SyntaxKind.JSDocAbstractTag:
535536
case SyntaxKind.JSDocClassTag:
536537
case SyntaxKind.JSDocPublicTag:
537538
case SyntaxKind.JSDocPrivateTag:
@@ -7443,6 +7444,9 @@ namespace ts {
74437444

74447445
let tag: JSDocTag | undefined;
74457446
switch (tagName.escapedText) {
7447+
case "abstract":
7448+
tag = parseSimpleTag(start, factory.createJSDocAbstractTag, tagName, margin, indentText);
7449+
break;
74467450
case "author":
74477451
tag = parseAuthorTag(start, tagName, margin, indentText);
74487452
break;

src/compiler/types.ts

+7
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ namespace ts {
378378
JSDocTag,
379379
JSDocAugmentsTag,
380380
JSDocImplementsTag,
381+
JSDocAbstractTag,
381382
JSDocAuthorTag,
382383
JSDocDeprecatedTag,
383384
JSDocClassTag,
@@ -3166,6 +3167,10 @@ namespace ts {
31663167
readonly class: ExpressionWithTypeArguments & { readonly expression: Identifier | PropertyAccessEntityNameExpression };
31673168
}
31683169

3170+
export interface JSDocAbstractTag extends JSDocTag {
3171+
readonly kind: SyntaxKind.JSDocAbstractTag;
3172+
}
3173+
31693174
export interface JSDocAuthorTag extends JSDocTag {
31703175
readonly kind: SyntaxKind.JSDocAuthorTag;
31713176
}
@@ -7160,6 +7165,8 @@ namespace ts {
71607165
updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | undefined): JSDocAugmentsTag;
71617166
createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string): JSDocImplementsTag;
71627167
updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment: string | undefined): JSDocImplementsTag;
7168+
createJSDocAbstractTag(tagName: Identifier | undefined, comment?: string): JSDocAbstractTag;
7169+
updateJSDocAbstractTag(node: JSDocAbstractTag, tagName: Identifier | undefined, comment: string | undefined): JSDocAbstractTag;
71637170
createJSDocAuthorTag(tagName: Identifier | undefined, comment?: string): JSDocAuthorTag;
71647171
updateJSDocAuthorTag(node: JSDocAuthorTag, tagName: Identifier | undefined, comment: string | undefined): JSDocAuthorTag;
71657172
createJSDocClassTag(tagName: Identifier | undefined, comment?: string): JSDocClassTag;

src/compiler/utilities.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4719,6 +4719,7 @@ namespace ts {
47194719
if (getJSDocPrivateTagNoCache(node)) flags |= ModifierFlags.Private;
47204720
if (getJSDocProtectedTagNoCache(node)) flags |= ModifierFlags.Protected;
47214721
if (getJSDocReadonlyTagNoCache(node)) flags |= ModifierFlags.Readonly;
4722+
if (getJSDocAbstractTagNoCache(node)) flags |= ModifierFlags.Abstract;
47224723
}
47234724
if (getJSDocDeprecatedTagNoCache(node)) flags |= ModifierFlags.Deprecated;
47244725
}

src/compiler/utilitiesPublic.ts

+4
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,10 @@ namespace ts {
767767
return getFirstJSDocTag(node, isJSDocReadonlyTag, /*noCache*/ true);
768768
}
769769

770+
export function getJSDocAbstractTagNoCache(node: Node): JSDocAbstractTag | undefined {
771+
return getFirstJSDocTag(node, isJSDocAbstractTag, /*noCache*/ true);
772+
}
773+
770774
/** Gets the JSDoc deprecated tag for the node if present */
771775
export function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefined {
772776
return getFirstJSDocTag(node, isJSDocDeprecatedTag);

tests/baselines/reference/api/tsserverlibrary.d.ts

+35-27
Original file line numberDiff line numberDiff line change
@@ -421,31 +421,32 @@ declare namespace ts {
421421
JSDocTag = 314,
422422
JSDocAugmentsTag = 315,
423423
JSDocImplementsTag = 316,
424-
JSDocAuthorTag = 317,
425-
JSDocDeprecatedTag = 318,
426-
JSDocClassTag = 319,
427-
JSDocPublicTag = 320,
428-
JSDocPrivateTag = 321,
429-
JSDocProtectedTag = 322,
430-
JSDocReadonlyTag = 323,
431-
JSDocCallbackTag = 324,
432-
JSDocEnumTag = 325,
433-
JSDocParameterTag = 326,
434-
JSDocReturnTag = 327,
435-
JSDocThisTag = 328,
436-
JSDocTypeTag = 329,
437-
JSDocTemplateTag = 330,
438-
JSDocTypedefTag = 331,
439-
JSDocSeeTag = 332,
440-
JSDocPropertyTag = 333,
441-
SyntaxList = 334,
442-
NotEmittedStatement = 335,
443-
PartiallyEmittedExpression = 336,
444-
CommaListExpression = 337,
445-
MergeDeclarationMarker = 338,
446-
EndOfDeclarationMarker = 339,
447-
SyntheticReferenceExpression = 340,
448-
Count = 341,
424+
JSDocAbstractTag = 317,
425+
JSDocAuthorTag = 318,
426+
JSDocDeprecatedTag = 319,
427+
JSDocClassTag = 320,
428+
JSDocPublicTag = 321,
429+
JSDocPrivateTag = 322,
430+
JSDocProtectedTag = 323,
431+
JSDocReadonlyTag = 324,
432+
JSDocCallbackTag = 325,
433+
JSDocEnumTag = 326,
434+
JSDocParameterTag = 327,
435+
JSDocReturnTag = 328,
436+
JSDocThisTag = 329,
437+
JSDocTypeTag = 330,
438+
JSDocTemplateTag = 331,
439+
JSDocTypedefTag = 332,
440+
JSDocSeeTag = 333,
441+
JSDocPropertyTag = 334,
442+
SyntaxList = 335,
443+
NotEmittedStatement = 336,
444+
PartiallyEmittedExpression = 337,
445+
CommaListExpression = 338,
446+
MergeDeclarationMarker = 339,
447+
EndOfDeclarationMarker = 340,
448+
SyntheticReferenceExpression = 341,
449+
Count = 342,
449450
FirstAssignment = 62,
450451
LastAssignment = 77,
451452
FirstCompoundAssignment = 63,
@@ -474,9 +475,9 @@ declare namespace ts {
474475
LastStatement = 248,
475476
FirstNode = 157,
476477
FirstJSDocNode = 301,
477-
LastJSDocNode = 333,
478+
LastJSDocNode = 334,
478479
FirstJSDocTagNode = 314,
479-
LastJSDocTagNode = 333,
480+
LastJSDocTagNode = 334,
480481
}
481482
export type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia;
482483
export type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral;
@@ -1768,6 +1769,9 @@ declare namespace ts {
17681769
readonly expression: Identifier | PropertyAccessEntityNameExpression;
17691770
};
17701771
}
1772+
export interface JSDocAbstractTag extends JSDocTag {
1773+
readonly kind: SyntaxKind.JSDocAbstractTag;
1774+
}
17711775
export interface JSDocAuthorTag extends JSDocTag {
17721776
readonly kind: SyntaxKind.JSDocAuthorTag;
17731777
}
@@ -3479,6 +3483,8 @@ declare namespace ts {
34793483
updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | undefined): JSDocAugmentsTag;
34803484
createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string): JSDocImplementsTag;
34813485
updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment: string | undefined): JSDocImplementsTag;
3486+
createJSDocAbstractTag(tagName: Identifier | undefined, comment?: string): JSDocAbstractTag;
3487+
updateJSDocAbstractTag(node: JSDocAbstractTag, tagName: Identifier | undefined, comment: string | undefined): JSDocAbstractTag;
34823488
createJSDocAuthorTag(tagName: Identifier | undefined, comment?: string): JSDocAuthorTag;
34833489
updateJSDocAuthorTag(node: JSDocAuthorTag, tagName: Identifier | undefined, comment: string | undefined): JSDocAuthorTag;
34843490
createJSDocClassTag(tagName: Identifier | undefined, comment?: string): JSDocClassTag;
@@ -4141,6 +4147,7 @@ declare namespace ts {
41414147
function getJSDocProtectedTag(node: Node): JSDocProtectedTag | undefined;
41424148
/** Gets the JSDoc protected tag for the node if present */
41434149
function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined;
4150+
function getJSDocAbstractTagNoCache(node: Node): JSDocAbstractTag | undefined;
41444151
/** Gets the JSDoc deprecated tag for the node if present */
41454152
function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefined;
41464153
/** Gets the JSDoc enum tag for the node if present */
@@ -4499,6 +4506,7 @@ declare namespace ts {
44994506
function isJSDocTypeLiteral(node: Node): node is JSDocTypeLiteral;
45004507
function isJSDocSignature(node: Node): node is JSDocSignature;
45014508
function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag;
4509+
function isJSDocAbstractTag(node: Node): node is JSDocAbstractTag;
45024510
function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag;
45034511
function isJSDocClassTag(node: Node): node is JSDocClassTag;
45044512
function isJSDocCallbackTag(node: Node): node is JSDocCallbackTag;

0 commit comments

Comments
 (0)