From 9dfbcfd8a32340f59282ef692957a0d81e4990f4 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Thu, 31 Dec 2020 10:06:36 +0200 Subject: [PATCH] feat(17227): add abstract JSDoc tag --- src/compiler/checker.ts | 24 +++++-- src/compiler/factory/nodeFactory.ts | 3 + src/compiler/factory/nodeTests.ts | 4 ++ src/compiler/parser.ts | 4 ++ src/compiler/types.ts | 7 +++ src/compiler/utilities.ts | 1 + src/compiler/utilitiesPublic.ts | 4 ++ .../reference/api/tsserverlibrary.d.ts | 62 +++++++++++-------- tests/baselines/reference/api/typescript.d.ts | 62 +++++++++++-------- .../reference/jsdocAbstract1.errors.txt | 11 ++++ tests/baselines/reference/jsdocAbstract1.js | 13 ++++ .../reference/jsdocAbstract1.symbols | 8 +++ .../baselines/reference/jsdocAbstract1.types | 9 +++ .../reference/jsdocAbstract2.errors.txt | 32 ++++++++++ tests/baselines/reference/jsdocAbstract2.js | 43 +++++++++++++ .../reference/jsdocAbstract2.symbols | 36 +++++++++++ .../baselines/reference/jsdocAbstract2.types | 37 +++++++++++ .../reference/jsdocAbstract3.errors.txt | 25 ++++++++ tests/baselines/reference/jsdocAbstract3.js | 30 +++++++++ .../reference/jsdocAbstract3.symbols | 24 +++++++ .../baselines/reference/jsdocAbstract3.types | 25 ++++++++ .../reference/jsdocAbstract4.errors.txt | 38 ++++++++++++ tests/baselines/reference/jsdocAbstract4.js | 34 ++++++++++ .../reference/jsdocAbstract4.symbols | 25 ++++++++ .../baselines/reference/jsdocAbstract4.types | 25 ++++++++ .../cases/conformance/jsdoc/jsdocAbstract1.ts | 11 ++++ .../cases/conformance/jsdoc/jsdocAbstract2.ts | 29 +++++++++ .../cases/conformance/jsdoc/jsdocAbstract3.ts | 21 +++++++ .../cases/conformance/jsdoc/jsdocAbstract4.ts | 23 +++++++ 29 files changed, 610 insertions(+), 60 deletions(-) create mode 100644 tests/baselines/reference/jsdocAbstract1.errors.txt create mode 100644 tests/baselines/reference/jsdocAbstract1.js create mode 100644 tests/baselines/reference/jsdocAbstract1.symbols create mode 100644 tests/baselines/reference/jsdocAbstract1.types create mode 100644 tests/baselines/reference/jsdocAbstract2.errors.txt create mode 100644 tests/baselines/reference/jsdocAbstract2.js create mode 100644 tests/baselines/reference/jsdocAbstract2.symbols create mode 100644 tests/baselines/reference/jsdocAbstract2.types create mode 100644 tests/baselines/reference/jsdocAbstract3.errors.txt create mode 100644 tests/baselines/reference/jsdocAbstract3.js create mode 100644 tests/baselines/reference/jsdocAbstract3.symbols create mode 100644 tests/baselines/reference/jsdocAbstract3.types create mode 100644 tests/baselines/reference/jsdocAbstract4.errors.txt create mode 100644 tests/baselines/reference/jsdocAbstract4.js create mode 100644 tests/baselines/reference/jsdocAbstract4.symbols create mode 100644 tests/baselines/reference/jsdocAbstract4.types create mode 100644 tests/cases/conformance/jsdoc/jsdocAbstract1.ts create mode 100644 tests/cases/conformance/jsdoc/jsdocAbstract2.ts create mode 100644 tests/cases/conformance/jsdoc/jsdocAbstract3.ts create mode 100644 tests/cases/conformance/jsdoc/jsdocAbstract4.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a3b147f25e71b..e841c7bc7278b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6800,6 +6800,7 @@ namespace ts { ...!length(baseTypes) ? [] : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))], ...!length(implementsExpressions) ? [] : [factory.createHeritageClause(SyntaxKind.ImplementsKeyword, implementsExpressions)] ]; + const modifiers = originalDecl && hasEffectiveModifier(originalDecl, ModifierFlags.Abstract) ? factory.createModifiersFromModifierFlags(ModifierFlags.Abstract) : undefined; const symbolProps = getNonInterhitedProperties(classType, baseTypes, getPropertiesOfType(classType)); const publicSymbolProps = filter(symbolProps, s => { // `valueDeclaration` could be undefined if inherited from @@ -6846,7 +6847,7 @@ namespace ts { context.enclosingDeclaration = oldEnclosing; addResult(setTextRange(factory.createClassDeclaration( /*decorators*/ undefined, - /*modifiers*/ undefined, + modifiers, localName, typeParamDecls, heritageClauses, @@ -28036,7 +28037,7 @@ namespace ts { // In the case of a merged class-module or class-interface declaration, // only the class declaration node will have the Abstract flag set. const valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol); - if (valueDecl && hasSyntacticModifier(valueDecl, ModifierFlags.Abstract)) { + if (valueDecl && hasEffectiveModifier(valueDecl, ModifierFlags.Abstract)) { error(node, Diagnostics.Cannot_create_an_instance_of_an_abstract_class); return resolveErrorCall(node); } @@ -29531,7 +29532,7 @@ namespace ts { if (type && type.flags & TypeFlags.Never) { error(getEffectiveReturnTypeNode(func), Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point); } - else if (type && !hasExplicitReturn) { + else if (type && !hasExplicitReturn && !hasEffectiveModifier(func, ModifierFlags.Abstract)) { // minimal check: function has syntactic return type annotation and no explicit return statements in the body // this function does not conform to the specification. // NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present @@ -31899,7 +31900,7 @@ namespace ts { // Abstract methods cannot have an implementation. // Extra checks are to avoid reporting multiple errors relating to the "abstractness" of the node. - if (hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration && node.body) { + if (hasEffectiveModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration && node.body && !isInJSFile(node)) { error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name)); } } @@ -31996,7 +31997,7 @@ namespace ts { checkSignatureDeclaration(node); if (node.kind === SyntaxKind.GetAccessor) { if (!(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { - if (!(node.flags & NodeFlags.HasExplicitReturn)) { + if (!(node.flags & NodeFlags.HasExplicitReturn) && !(isInJSFile(node) && hasEffectiveModifier(node, ModifierFlags.Abstract))) { error(node.name, Diagnostics.A_get_accessor_must_return_a_value); } } @@ -33277,6 +33278,15 @@ namespace ts { checkSignatureDeclaration(node); } + function checkJSDocAbstractTag(node: JSDocAbstractTag): void { + const host = getEffectiveJSDocHost(node); + if (host && isClassElement(host)) { + if (!hasEffectiveModifier(host.parent, ModifierFlags.Abstract)) { + error(host, Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class); + } + } + } + function checkJSDocImplementsTag(node: JSDocImplementsTag): void { const classLike = getEffectiveJSDocHost(node); if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) { @@ -36969,6 +36979,8 @@ namespace ts { return checkImportType(node); case SyntaxKind.NamedTupleMember: return checkNamedTupleMember(node); + case SyntaxKind.JSDocAbstractTag: + return checkJSDocAbstractTag(node); case SyntaxKind.JSDocAugmentsTag: return checkJSDocAugmentsTag(node as JSDocAugmentsTag); case SyntaxKind.JSDocImplementsTag: @@ -39851,7 +39863,7 @@ namespace ts { return grammarErrorAtPos(accessor, accessor.end - 1, ";".length, Diagnostics._0_expected, "{"); } } - if (accessor.body && hasSyntacticModifier(accessor, ModifierFlags.Abstract)) { + if (accessor.body && hasEffectiveModifier(accessor, ModifierFlags.Abstract) && !isInJSFile(accessor)) { return grammarErrorOnNode(accessor, Diagnostics.An_abstract_accessor_cannot_have_an_implementation); } if (accessor.typeParameters) { diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 176c9154dcd38..1d16d52c357cd 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -354,6 +354,8 @@ namespace ts { get updateJSDocThisTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocThisTag); }, get createJSDocEnumTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocEnumTag); }, get updateJSDocEnumTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocEnumTag); }, + get createJSDocAbstractTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocAbstractTag); }, + get updateJSDocAbstractTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocAbstractTag); }, get createJSDocAuthorTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocAuthorTag); }, get updateJSDocAuthorTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocAuthorTag); }, get createJSDocClassTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocClassTag); }, @@ -5859,6 +5861,7 @@ namespace ts { case SyntaxKind.JSDocReturnTag: return "returns"; case SyntaxKind.JSDocThisTag: return "this"; case SyntaxKind.JSDocEnumTag: return "enum"; + case SyntaxKind.JSDocAbstractTag: return "abstract"; case SyntaxKind.JSDocAuthorTag: return "author"; case SyntaxKind.JSDocClassTag: return "class"; case SyntaxKind.JSDocPublicTag: return "public"; diff --git a/src/compiler/factory/nodeTests.ts b/src/compiler/factory/nodeTests.ts index 71b329e46d65c..f37c36134edea 100644 --- a/src/compiler/factory/nodeTests.ts +++ b/src/compiler/factory/nodeTests.ts @@ -757,6 +757,10 @@ namespace ts { return node.kind === SyntaxKind.JSDocAugmentsTag; } + export function isJSDocAbstractTag(node: Node): node is JSDocAbstractTag { + return node.kind === SyntaxKind.JSDocAbstractTag; + } + export function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag { return node.kind === SyntaxKind.JSDocAuthorTag; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b3ae9b9f7b638..404e3041700cc 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -532,6 +532,7 @@ namespace ts { case SyntaxKind.JSDocTypeLiteral: return forEach((node as JSDocTypeLiteral).jsDocPropertyTags, cbNode); case SyntaxKind.JSDocTag: + case SyntaxKind.JSDocAbstractTag: case SyntaxKind.JSDocClassTag: case SyntaxKind.JSDocPublicTag: case SyntaxKind.JSDocPrivateTag: @@ -7443,6 +7444,9 @@ namespace ts { let tag: JSDocTag | undefined; switch (tagName.escapedText) { + case "abstract": + tag = parseSimpleTag(start, factory.createJSDocAbstractTag, tagName, margin, indentText); + break; case "author": tag = parseAuthorTag(start, tagName, margin, indentText); break; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 81181164a7971..57af96debfe18 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -378,6 +378,7 @@ namespace ts { JSDocTag, JSDocAugmentsTag, JSDocImplementsTag, + JSDocAbstractTag, JSDocAuthorTag, JSDocDeprecatedTag, JSDocClassTag, @@ -3166,6 +3167,10 @@ namespace ts { readonly class: ExpressionWithTypeArguments & { readonly expression: Identifier | PropertyAccessEntityNameExpression }; } + export interface JSDocAbstractTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocAbstractTag; + } + export interface JSDocAuthorTag extends JSDocTag { readonly kind: SyntaxKind.JSDocAuthorTag; } @@ -7160,6 +7165,8 @@ namespace ts { updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | undefined): JSDocAugmentsTag; createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string): JSDocImplementsTag; updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment: string | undefined): JSDocImplementsTag; + createJSDocAbstractTag(tagName: Identifier | undefined, comment?: string): JSDocAbstractTag; + updateJSDocAbstractTag(node: JSDocAbstractTag, tagName: Identifier | undefined, comment: string | undefined): JSDocAbstractTag; createJSDocAuthorTag(tagName: Identifier | undefined, comment?: string): JSDocAuthorTag; updateJSDocAuthorTag(node: JSDocAuthorTag, tagName: Identifier | undefined, comment: string | undefined): JSDocAuthorTag; createJSDocClassTag(tagName: Identifier | undefined, comment?: string): JSDocClassTag; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 12b815995cfa7..016476a78fbeb 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4719,6 +4719,7 @@ namespace ts { if (getJSDocPrivateTagNoCache(node)) flags |= ModifierFlags.Private; if (getJSDocProtectedTagNoCache(node)) flags |= ModifierFlags.Protected; if (getJSDocReadonlyTagNoCache(node)) flags |= ModifierFlags.Readonly; + if (getJSDocAbstractTagNoCache(node)) flags |= ModifierFlags.Abstract; } if (getJSDocDeprecatedTagNoCache(node)) flags |= ModifierFlags.Deprecated; } diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 6722e7ad5be1f..149e90303c4fe 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -767,6 +767,10 @@ namespace ts { return getFirstJSDocTag(node, isJSDocReadonlyTag, /*noCache*/ true); } + export function getJSDocAbstractTagNoCache(node: Node): JSDocAbstractTag | undefined { + return getFirstJSDocTag(node, isJSDocAbstractTag, /*noCache*/ true); + } + /** Gets the JSDoc deprecated tag for the node if present */ export function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefined { return getFirstJSDocTag(node, isJSDocDeprecatedTag); diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index f2795baa971fd..a0378982c956f 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -421,31 +421,32 @@ declare namespace ts { JSDocTag = 314, JSDocAugmentsTag = 315, JSDocImplementsTag = 316, - JSDocAuthorTag = 317, - JSDocDeprecatedTag = 318, - JSDocClassTag = 319, - JSDocPublicTag = 320, - JSDocPrivateTag = 321, - JSDocProtectedTag = 322, - JSDocReadonlyTag = 323, - JSDocCallbackTag = 324, - JSDocEnumTag = 325, - JSDocParameterTag = 326, - JSDocReturnTag = 327, - JSDocThisTag = 328, - JSDocTypeTag = 329, - JSDocTemplateTag = 330, - JSDocTypedefTag = 331, - JSDocSeeTag = 332, - JSDocPropertyTag = 333, - SyntaxList = 334, - NotEmittedStatement = 335, - PartiallyEmittedExpression = 336, - CommaListExpression = 337, - MergeDeclarationMarker = 338, - EndOfDeclarationMarker = 339, - SyntheticReferenceExpression = 340, - Count = 341, + JSDocAbstractTag = 317, + JSDocAuthorTag = 318, + JSDocDeprecatedTag = 319, + JSDocClassTag = 320, + JSDocPublicTag = 321, + JSDocPrivateTag = 322, + JSDocProtectedTag = 323, + JSDocReadonlyTag = 324, + JSDocCallbackTag = 325, + JSDocEnumTag = 326, + JSDocParameterTag = 327, + JSDocReturnTag = 328, + JSDocThisTag = 329, + JSDocTypeTag = 330, + JSDocTemplateTag = 331, + JSDocTypedefTag = 332, + JSDocSeeTag = 333, + JSDocPropertyTag = 334, + SyntaxList = 335, + NotEmittedStatement = 336, + PartiallyEmittedExpression = 337, + CommaListExpression = 338, + MergeDeclarationMarker = 339, + EndOfDeclarationMarker = 340, + SyntheticReferenceExpression = 341, + Count = 342, FirstAssignment = 62, LastAssignment = 77, FirstCompoundAssignment = 63, @@ -474,9 +475,9 @@ declare namespace ts { LastStatement = 248, FirstNode = 157, FirstJSDocNode = 301, - LastJSDocNode = 333, + LastJSDocNode = 334, FirstJSDocTagNode = 314, - LastJSDocTagNode = 333, + LastJSDocTagNode = 334, } export type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia; export type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral; @@ -1768,6 +1769,9 @@ declare namespace ts { readonly expression: Identifier | PropertyAccessEntityNameExpression; }; } + export interface JSDocAbstractTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocAbstractTag; + } export interface JSDocAuthorTag extends JSDocTag { readonly kind: SyntaxKind.JSDocAuthorTag; } @@ -3479,6 +3483,8 @@ declare namespace ts { updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | undefined): JSDocAugmentsTag; createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string): JSDocImplementsTag; updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment: string | undefined): JSDocImplementsTag; + createJSDocAbstractTag(tagName: Identifier | undefined, comment?: string): JSDocAbstractTag; + updateJSDocAbstractTag(node: JSDocAbstractTag, tagName: Identifier | undefined, comment: string | undefined): JSDocAbstractTag; createJSDocAuthorTag(tagName: Identifier | undefined, comment?: string): JSDocAuthorTag; updateJSDocAuthorTag(node: JSDocAuthorTag, tagName: Identifier | undefined, comment: string | undefined): JSDocAuthorTag; createJSDocClassTag(tagName: Identifier | undefined, comment?: string): JSDocClassTag; @@ -4141,6 +4147,7 @@ declare namespace ts { function getJSDocProtectedTag(node: Node): JSDocProtectedTag | undefined; /** Gets the JSDoc protected tag for the node if present */ function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined; + function getJSDocAbstractTagNoCache(node: Node): JSDocAbstractTag | undefined; /** Gets the JSDoc deprecated tag for the node if present */ function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefined; /** Gets the JSDoc enum tag for the node if present */ @@ -4499,6 +4506,7 @@ declare namespace ts { function isJSDocTypeLiteral(node: Node): node is JSDocTypeLiteral; function isJSDocSignature(node: Node): node is JSDocSignature; function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag; + function isJSDocAbstractTag(node: Node): node is JSDocAbstractTag; function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag; function isJSDocClassTag(node: Node): node is JSDocClassTag; function isJSDocCallbackTag(node: Node): node is JSDocCallbackTag; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 0f9c37e24b4ce..81662258e5251 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -421,31 +421,32 @@ declare namespace ts { JSDocTag = 314, JSDocAugmentsTag = 315, JSDocImplementsTag = 316, - JSDocAuthorTag = 317, - JSDocDeprecatedTag = 318, - JSDocClassTag = 319, - JSDocPublicTag = 320, - JSDocPrivateTag = 321, - JSDocProtectedTag = 322, - JSDocReadonlyTag = 323, - JSDocCallbackTag = 324, - JSDocEnumTag = 325, - JSDocParameterTag = 326, - JSDocReturnTag = 327, - JSDocThisTag = 328, - JSDocTypeTag = 329, - JSDocTemplateTag = 330, - JSDocTypedefTag = 331, - JSDocSeeTag = 332, - JSDocPropertyTag = 333, - SyntaxList = 334, - NotEmittedStatement = 335, - PartiallyEmittedExpression = 336, - CommaListExpression = 337, - MergeDeclarationMarker = 338, - EndOfDeclarationMarker = 339, - SyntheticReferenceExpression = 340, - Count = 341, + JSDocAbstractTag = 317, + JSDocAuthorTag = 318, + JSDocDeprecatedTag = 319, + JSDocClassTag = 320, + JSDocPublicTag = 321, + JSDocPrivateTag = 322, + JSDocProtectedTag = 323, + JSDocReadonlyTag = 324, + JSDocCallbackTag = 325, + JSDocEnumTag = 326, + JSDocParameterTag = 327, + JSDocReturnTag = 328, + JSDocThisTag = 329, + JSDocTypeTag = 330, + JSDocTemplateTag = 331, + JSDocTypedefTag = 332, + JSDocSeeTag = 333, + JSDocPropertyTag = 334, + SyntaxList = 335, + NotEmittedStatement = 336, + PartiallyEmittedExpression = 337, + CommaListExpression = 338, + MergeDeclarationMarker = 339, + EndOfDeclarationMarker = 340, + SyntheticReferenceExpression = 341, + Count = 342, FirstAssignment = 62, LastAssignment = 77, FirstCompoundAssignment = 63, @@ -474,9 +475,9 @@ declare namespace ts { LastStatement = 248, FirstNode = 157, FirstJSDocNode = 301, - LastJSDocNode = 333, + LastJSDocNode = 334, FirstJSDocTagNode = 314, - LastJSDocTagNode = 333, + LastJSDocTagNode = 334, } export type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia; export type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral; @@ -1768,6 +1769,9 @@ declare namespace ts { readonly expression: Identifier | PropertyAccessEntityNameExpression; }; } + export interface JSDocAbstractTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocAbstractTag; + } export interface JSDocAuthorTag extends JSDocTag { readonly kind: SyntaxKind.JSDocAuthorTag; } @@ -3479,6 +3483,8 @@ declare namespace ts { updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | undefined): JSDocAugmentsTag; createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string): JSDocImplementsTag; updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment: string | undefined): JSDocImplementsTag; + createJSDocAbstractTag(tagName: Identifier | undefined, comment?: string): JSDocAbstractTag; + updateJSDocAbstractTag(node: JSDocAbstractTag, tagName: Identifier | undefined, comment: string | undefined): JSDocAbstractTag; createJSDocAuthorTag(tagName: Identifier | undefined, comment?: string): JSDocAuthorTag; updateJSDocAuthorTag(node: JSDocAuthorTag, tagName: Identifier | undefined, comment: string | undefined): JSDocAuthorTag; createJSDocClassTag(tagName: Identifier | undefined, comment?: string): JSDocClassTag; @@ -4141,6 +4147,7 @@ declare namespace ts { function getJSDocProtectedTag(node: Node): JSDocProtectedTag | undefined; /** Gets the JSDoc protected tag for the node if present */ function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined; + function getJSDocAbstractTagNoCache(node: Node): JSDocAbstractTag | undefined; /** Gets the JSDoc deprecated tag for the node if present */ function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefined; /** Gets the JSDoc enum tag for the node if present */ @@ -4499,6 +4506,7 @@ declare namespace ts { function isJSDocTypeLiteral(node: Node): node is JSDocTypeLiteral; function isJSDocSignature(node: Node): node is JSDocSignature; function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag; + function isJSDocAbstractTag(node: Node): node is JSDocAbstractTag; function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag; function isJSDocClassTag(node: Node): node is JSDocClassTag; function isJSDocCallbackTag(node: Node): node is JSDocCallbackTag; diff --git a/tests/baselines/reference/jsdocAbstract1.errors.txt b/tests/baselines/reference/jsdocAbstract1.errors.txt new file mode 100644 index 0000000000000..a4f6aeb282df9 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract1.errors.txt @@ -0,0 +1,11 @@ +tests/cases/conformance/jsdoc/jsdocAbstract1.js(4,1): error TS2511: Cannot create an instance of an abstract class. + + +==== tests/cases/conformance/jsdoc/jsdocAbstract1.js (1 errors) ==== + /** @abstract */ + class A { + } + new A() + ~~~~~~~ +!!! error TS2511: Cannot create an instance of an abstract class. + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocAbstract1.js b/tests/baselines/reference/jsdocAbstract1.js new file mode 100644 index 0000000000000..3d1d93c83d0f8 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract1.js @@ -0,0 +1,13 @@ +//// [jsdocAbstract1.js] +/** @abstract */ +class A { +} +new A() + + + + +//// [jsdocAbstract1.d.ts] +/** @abstract */ +declare abstract class A { +} diff --git a/tests/baselines/reference/jsdocAbstract1.symbols b/tests/baselines/reference/jsdocAbstract1.symbols new file mode 100644 index 0000000000000..e7f7a3f13f832 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract1.symbols @@ -0,0 +1,8 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract1.js === +/** @abstract */ +class A { +>A : Symbol(A, Decl(jsdocAbstract1.js, 0, 0)) +} +new A() +>A : Symbol(A, Decl(jsdocAbstract1.js, 0, 0)) + diff --git a/tests/baselines/reference/jsdocAbstract1.types b/tests/baselines/reference/jsdocAbstract1.types new file mode 100644 index 0000000000000..507cbe62409a3 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract1.types @@ -0,0 +1,9 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract1.js === +/** @abstract */ +class A { +>A : A +} +new A() +>new A() : any +>A : typeof A + diff --git a/tests/baselines/reference/jsdocAbstract2.errors.txt b/tests/baselines/reference/jsdocAbstract2.errors.txt new file mode 100644 index 0000000000000..3f11604bf7162 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract2.errors.txt @@ -0,0 +1,32 @@ +error TS-1: Pre-emit (2) and post-emit (1) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here! +tests/cases/conformance/jsdoc/jsdocAbstract2.js(18,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'foo' from class 'A'. + + +!!! error TS-1: Pre-emit (2) and post-emit (1) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here! +!!! related TS-1: The excess diagnostics are: +==== tests/cases/conformance/jsdoc/jsdocAbstract2.js (1 errors) ==== + /** @abstract */ + class A { + /** + * @abstract + * @returns {number} + */ + foo() {} + } + + // ok + class B extends A { + foo() { + return 1; + } + } + + // error + class C extends A {} + ~ +!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'foo' from class 'A'. + + // ok + /** @abstract */ + class D extends A {} + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocAbstract2.js b/tests/baselines/reference/jsdocAbstract2.js new file mode 100644 index 0000000000000..38ef1a530f5df --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract2.js @@ -0,0 +1,43 @@ +//// [jsdocAbstract2.js] +/** @abstract */ +class A { + /** + * @abstract + * @returns {number} + */ + foo() {} +} + +// ok +class B extends A { + foo() { + return 1; + } +} + +// error +class C extends A {} + +// ok +/** @abstract */ +class D extends A {} + + + + +//// [jsdocAbstract2.d.ts] +/** @abstract */ +declare abstract class A { + /** + * @abstract + * @returns {number} + */ + abstract foo(): number; +} +declare class B extends A { +} +declare class C extends A { +} +/** @abstract */ +declare abstract class D extends A { +} diff --git a/tests/baselines/reference/jsdocAbstract2.symbols b/tests/baselines/reference/jsdocAbstract2.symbols new file mode 100644 index 0000000000000..53f7da92b0d8e --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract2.symbols @@ -0,0 +1,36 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract2.js === +/** @abstract */ +class A { +>A : Symbol(A, Decl(jsdocAbstract2.js, 0, 0)) + + /** + * @abstract + * @returns {number} + */ + foo() {} +>foo : Symbol(A.foo, Decl(jsdocAbstract2.js, 1, 9)) +} + +// ok +class B extends A { +>B : Symbol(B, Decl(jsdocAbstract2.js, 7, 1)) +>A : Symbol(A, Decl(jsdocAbstract2.js, 0, 0)) + + foo() { +>foo : Symbol(B.foo, Decl(jsdocAbstract2.js, 10, 19)) + + return 1; + } +} + +// error +class C extends A {} +>C : Symbol(C, Decl(jsdocAbstract2.js, 14, 1)) +>A : Symbol(A, Decl(jsdocAbstract2.js, 0, 0)) + +// ok +/** @abstract */ +class D extends A {} +>D : Symbol(D, Decl(jsdocAbstract2.js, 17, 20)) +>A : Symbol(A, Decl(jsdocAbstract2.js, 0, 0)) + diff --git a/tests/baselines/reference/jsdocAbstract2.types b/tests/baselines/reference/jsdocAbstract2.types new file mode 100644 index 0000000000000..ad8a2ce0124c4 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract2.types @@ -0,0 +1,37 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract2.js === +/** @abstract */ +class A { +>A : A + + /** + * @abstract + * @returns {number} + */ + foo() {} +>foo : () => number +} + +// ok +class B extends A { +>B : B +>A : A + + foo() { +>foo : () => number + + return 1; +>1 : 1 + } +} + +// error +class C extends A {} +>C : C +>A : A + +// ok +/** @abstract */ +class D extends A {} +>D : D +>A : A + diff --git a/tests/baselines/reference/jsdocAbstract3.errors.txt b/tests/baselines/reference/jsdocAbstract3.errors.txt new file mode 100644 index 0000000000000..a142e51936a8f --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract3.errors.txt @@ -0,0 +1,25 @@ +tests/cases/conformance/jsdoc/jsdocAbstract3.js(11,5): error TS2416: Property 'foo' in type 'B' is not assignable to the same property in base type 'A'. + Type '() => string' is not assignable to type '() => number'. + Type 'string' is not assignable to type 'number'. + + +==== tests/cases/conformance/jsdoc/jsdocAbstract3.js (1 errors) ==== + /** @abstract */ + class A { + /** + * @abstract + * @returns {number} + */ + foo() {} + } + + class B extends A { + foo() { + ~~~ +!!! error TS2416: Property 'foo' in type 'B' is not assignable to the same property in base type 'A'. +!!! error TS2416: Type '() => string' is not assignable to type '() => number'. +!!! error TS2416: Type 'string' is not assignable to type 'number'. + return ""; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocAbstract3.js b/tests/baselines/reference/jsdocAbstract3.js new file mode 100644 index 0000000000000..7a096acf43166 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract3.js @@ -0,0 +1,30 @@ +//// [jsdocAbstract3.js] +/** @abstract */ +class A { + /** + * @abstract + * @returns {number} + */ + foo() {} +} + +class B extends A { + foo() { + return ""; + } +} + + + + +//// [jsdocAbstract3.d.ts] +/** @abstract */ +declare abstract class A { + /** + * @abstract + * @returns {number} + */ + abstract foo(): number; +} +declare class B extends A { +} diff --git a/tests/baselines/reference/jsdocAbstract3.symbols b/tests/baselines/reference/jsdocAbstract3.symbols new file mode 100644 index 0000000000000..39d42d605cdaf --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract3.symbols @@ -0,0 +1,24 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract3.js === +/** @abstract */ +class A { +>A : Symbol(A, Decl(jsdocAbstract3.js, 0, 0)) + + /** + * @abstract + * @returns {number} + */ + foo() {} +>foo : Symbol(A.foo, Decl(jsdocAbstract3.js, 1, 9)) +} + +class B extends A { +>B : Symbol(B, Decl(jsdocAbstract3.js, 7, 1)) +>A : Symbol(A, Decl(jsdocAbstract3.js, 0, 0)) + + foo() { +>foo : Symbol(B.foo, Decl(jsdocAbstract3.js, 9, 19)) + + return ""; + } +} + diff --git a/tests/baselines/reference/jsdocAbstract3.types b/tests/baselines/reference/jsdocAbstract3.types new file mode 100644 index 0000000000000..42a3f9f50e17d --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract3.types @@ -0,0 +1,25 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract3.js === +/** @abstract */ +class A { +>A : A + + /** + * @abstract + * @returns {number} + */ + foo() {} +>foo : () => number +} + +class B extends A { +>B : B +>A : A + + foo() { +>foo : () => string + + return ""; +>"" : "" + } +} + diff --git a/tests/baselines/reference/jsdocAbstract4.errors.txt b/tests/baselines/reference/jsdocAbstract4.errors.txt new file mode 100644 index 0000000000000..ec9d1d43fa545 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract4.errors.txt @@ -0,0 +1,38 @@ +tests/cases/conformance/jsdoc/jsdocAbstract4.js(3,5): error TS1244: Abstract methods can only appear within an abstract class. +tests/cases/conformance/jsdoc/jsdocAbstract4.js(6,12): error TS1244: Abstract methods can only appear within an abstract class. +tests/cases/conformance/jsdoc/jsdocAbstract4.js(9,5): error TS1244: Abstract methods can only appear within an abstract class. +tests/cases/conformance/jsdoc/jsdocAbstract4.js(12,9): error TS1244: Abstract methods can only appear within an abstract class. +tests/cases/conformance/jsdoc/jsdocAbstract4.js(15,9): error TS1049: A 'set' accessor must have exactly one parameter. +tests/cases/conformance/jsdoc/jsdocAbstract4.js(15,9): error TS1244: Abstract methods can only appear within an abstract class. + + +==== tests/cases/conformance/jsdoc/jsdocAbstract4.js (6 errors) ==== + class Foo { + /** @abstract */ + m1() {} + ~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + + /** @abstract */ + static m2() {} + ~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + + /** @abstract */ + p1; + ~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + + /** @abstract */ + get p2() {} + ~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + + /** @abstract */ + set p2() {} + ~~ +!!! error TS1049: A 'set' accessor must have exactly one parameter. + ~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + } + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocAbstract4.js b/tests/baselines/reference/jsdocAbstract4.js new file mode 100644 index 0000000000000..4a609c70c92c0 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract4.js @@ -0,0 +1,34 @@ +//// [jsdocAbstract4.js] +class Foo { + /** @abstract */ + m1() {} + + /** @abstract */ + static m2() {} + + /** @abstract */ + p1; + + /** @abstract */ + get p2() {} + + /** @abstract */ + set p2() {} +} + + + + +//// [jsdocAbstract4.d.ts] +declare class Foo { + /** @abstract */ + abstract static m2(): void; + /** @abstract */ + abstract m1(): void; + /** @abstract */ + abstract p1: any; + /** @abstract */ + abstract set p2(arg: void); + /** @abstract */ + abstract get p2(): void; +} diff --git a/tests/baselines/reference/jsdocAbstract4.symbols b/tests/baselines/reference/jsdocAbstract4.symbols new file mode 100644 index 0000000000000..b67cd63d8a5cd --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract4.symbols @@ -0,0 +1,25 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract4.js === +class Foo { +>Foo : Symbol(Foo, Decl(jsdocAbstract4.js, 0, 0)) + + /** @abstract */ + m1() {} +>m1 : Symbol(Foo.m1, Decl(jsdocAbstract4.js, 0, 11)) + + /** @abstract */ + static m2() {} +>m2 : Symbol(Foo.m2, Decl(jsdocAbstract4.js, 2, 11)) + + /** @abstract */ + p1; +>p1 : Symbol(Foo.p1, Decl(jsdocAbstract4.js, 5, 18)) + + /** @abstract */ + get p2() {} +>p2 : Symbol(Foo.p2, Decl(jsdocAbstract4.js, 8, 7), Decl(jsdocAbstract4.js, 11, 15)) + + /** @abstract */ + set p2() {} +>p2 : Symbol(Foo.p2, Decl(jsdocAbstract4.js, 8, 7), Decl(jsdocAbstract4.js, 11, 15)) +} + diff --git a/tests/baselines/reference/jsdocAbstract4.types b/tests/baselines/reference/jsdocAbstract4.types new file mode 100644 index 0000000000000..022723d32378f --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract4.types @@ -0,0 +1,25 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract4.js === +class Foo { +>Foo : Foo + + /** @abstract */ + m1() {} +>m1 : () => void + + /** @abstract */ + static m2() {} +>m2 : () => void + + /** @abstract */ + p1; +>p1 : any + + /** @abstract */ + get p2() {} +>p2 : void + + /** @abstract */ + set p2() {} +>p2 : void +} + diff --git a/tests/cases/conformance/jsdoc/jsdocAbstract1.ts b/tests/cases/conformance/jsdoc/jsdocAbstract1.ts new file mode 100644 index 0000000000000..deb5e35fe970f --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocAbstract1.ts @@ -0,0 +1,11 @@ +// @allowJs: true +// @checkJs: true +// @target: esnext +// @declaration: true +// @emitDeclarationOnly: true +// @Filename: jsdocAbstract1.js + +/** @abstract */ +class A { +} +new A() diff --git a/tests/cases/conformance/jsdoc/jsdocAbstract2.ts b/tests/cases/conformance/jsdoc/jsdocAbstract2.ts new file mode 100644 index 0000000000000..db559ae387dfa --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocAbstract2.ts @@ -0,0 +1,29 @@ +// @allowJs: true +// @checkJs: true +// @target: esnext +// @declaration: true +// @emitDeclarationOnly: true +// @Filename: jsdocAbstract2.js + +/** @abstract */ +class A { + /** + * @abstract + * @returns {number} + */ + foo() {} +} + +// ok +class B extends A { + foo() { + return 1; + } +} + +// error +class C extends A {} + +// ok +/** @abstract */ +class D extends A {} diff --git a/tests/cases/conformance/jsdoc/jsdocAbstract3.ts b/tests/cases/conformance/jsdoc/jsdocAbstract3.ts new file mode 100644 index 0000000000000..4376f5f4725c6 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocAbstract3.ts @@ -0,0 +1,21 @@ +// @allowJs: true +// @checkJs: true +// @target: esnext +// @declaration: true +// @emitDeclarationOnly: true +// @Filename: jsdocAbstract3.js + +/** @abstract */ +class A { + /** + * @abstract + * @returns {number} + */ + foo() {} +} + +class B extends A { + foo() { + return ""; + } +} diff --git a/tests/cases/conformance/jsdoc/jsdocAbstract4.ts b/tests/cases/conformance/jsdoc/jsdocAbstract4.ts new file mode 100644 index 0000000000000..aeea63a28ac82 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocAbstract4.ts @@ -0,0 +1,23 @@ +// @allowJs: true +// @checkJs: true +// @target: esnext +// @declaration: true +// @emitDeclarationOnly: true +// @Filename: jsdocAbstract4.js + +class Foo { + /** @abstract */ + m1() {} + + /** @abstract */ + static m2() {} + + /** @abstract */ + p1; + + /** @abstract */ + get p2() {} + + /** @abstract */ + set p2() {} +}