diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ada4288903..f8ffddaa60 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6611,6 +6611,9 @@ namespace ts { let tag: JSDocTag | undefined; switch (tagName.escapedText) { + case "author": + tag = parseAuthorTag(start, tagName); + break; case "augments": case "extends": tag = parseAugmentsTag(start, tagName); @@ -6874,6 +6877,69 @@ namespace ts { return finishNode(result); } + function parseAuthorTag(start: number, tagName: Identifier): JSDocAuthorTag { + const result = createNode(SyntaxKind.JSDocAuthorTag, start); + result.tagName = tagName; + + const comment = tryParse(() => tryParseAuthorNameAndEmail()); + + if (comment) { + result.comment = comment; + } + + return finishNode(result); + } + + function tryParseAuthorNameAndEmail(): string | undefined { + const comments: string[] = []; + let seenLessThan = false; + let seenGreaterThan = false; + let seenAtToken = false; + let token = scanner.getToken(); + + loop: while (true) { + switch (token) { + case SyntaxKind.Identifier: + case SyntaxKind.WhitespaceTrivia: + case SyntaxKind.DotToken: + comments.push(scanner.getTokenText()); + break; + case SyntaxKind.LessThanToken: + if (seenLessThan || seenAtToken || seenGreaterThan) { + return; + } + seenLessThan = true; + comments.push(scanner.getTokenText()); + break; + case SyntaxKind.GreaterThanToken: + if (!seenLessThan || !seenAtToken || seenGreaterThan) { + return; + } + + seenGreaterThan = true; + comments.push(scanner.getTokenText()); + break loop; + case SyntaxKind.AtToken: + if (seenAtToken || !seenLessThan || seenGreaterThan) { + return; + } + + seenAtToken = true; + comments.push(scanner.getTokenText()); + break; + case SyntaxKind.NewLineTrivia: + case SyntaxKind.EndOfFileToken: + break loop; + } + + token = nextJSDocToken(); + } + + if (seenLessThan && seenAtToken && seenGreaterThan) { + return comments.length === 0 ? undefined : comments.join(""); + } + } + function parseAugmentsTag(start: number, tagName: Identifier): JSDocAugmentsTag { const result = createNode(SyntaxKind.JSDocAugmentsTag, start); result.tagName = tagName; diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 36ac8adfa9..256e41629a 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -2086,6 +2086,8 @@ namespace ts { return token = SyntaxKind.CloseBracketToken; case CharacterCodes.lessThan: return token = SyntaxKind.LessThanToken; + case CharacterCodes.greaterThan: + return token = SyntaxKind.GreaterThanToken; case CharacterCodes.equals: return token = SyntaxKind.EqualsToken; case CharacterCodes.comma: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0b952a4d00..432d1dccba 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -17,6 +17,7 @@ namespace ts { | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken + | SyntaxKind.GreaterThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken @@ -459,6 +460,7 @@ namespace ts { JSDocSignature, JSDocTag, JSDocAugmentsTag, + JSDocAuthorTag, JSDocClassTag, JSDocCallbackTag, JSDocEnumTag, @@ -2455,6 +2457,10 @@ namespace ts { class: ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression }; } + export interface JSDocAuthorTag extends JSDocTag { + kind: SyntaxKind.JSDocAuthorTag; + } + export interface JSDocClassTag extends JSDocTag { kind: SyntaxKind.JSDocClassTag; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2e6c3ae4f8..b72a30ffba 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6116,6 +6116,10 @@ namespace ts { return node.kind === SyntaxKind.JSDocComment; } + export function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag { + return node.kind === SyntaxKind.JSDocAuthorTag; + } + export function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag { return node.kind === SyntaxKind.JSDocAugmentsTag; } diff --git a/src/testRunner/unittests/jsDocParsing.ts b/src/testRunner/unittests/jsDocParsing.ts index 4171a330f3..59775862e9 100644 --- a/src/testRunner/unittests/jsDocParsing.ts +++ b/src/testRunner/unittests/jsDocParsing.ts @@ -313,6 +313,10 @@ namespace ts { * {@link first link} * Inside {@link link text} thing * @see {@link second link text} and {@link Foo|a foo} as well. + */`); + parsesCorrectly("authorTag", +`/** + * @author John Doe */`); }); }); diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.authorTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.authorTag.json new file mode 100644 index 0000000000..5239e57649 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.authorTag.json @@ -0,0 +1,22 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 50, + "tags": { + "0": { + "kind": "JSDocAuthorTag", + "pos": 7, + "end": 45, + "tagName": { + "kind": "Identifier", + "pos": 8, + "end": 14, + "escapedText": "author" + }, + "comment": "John Doe " + }, + "length": 1, + "pos": 7, + "end": 45 + } +} \ No newline at end of file diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 3f31d83d4f..0d55487a4a 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -72,7 +72,7 @@ declare namespace ts { pos: number; end: number; } - type JSDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.BacktickToken | SyntaxKind.Unknown | KeywordSyntaxKind; + type JSDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.GreaterThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.BacktickToken | SyntaxKind.Unknown | KeywordSyntaxKind; type KeywordSyntaxKind = SyntaxKind.AbstractKeyword | SyntaxKind.AnyKeyword | SyntaxKind.AsKeyword | SyntaxKind.BigIntKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.BreakKeyword | SyntaxKind.CaseKeyword | SyntaxKind.CatchKeyword | SyntaxKind.ClassKeyword | SyntaxKind.ContinueKeyword | SyntaxKind.ConstKeyword | SyntaxKind.ConstructorKeyword | SyntaxKind.DebuggerKeyword | SyntaxKind.DeclareKeyword | SyntaxKind.DefaultKeyword | SyntaxKind.DeleteKeyword | SyntaxKind.DoKeyword | SyntaxKind.ElseKeyword | SyntaxKind.EnumKeyword | SyntaxKind.ExportKeyword | SyntaxKind.ExtendsKeyword | SyntaxKind.FalseKeyword | SyntaxKind.FinallyKeyword | SyntaxKind.ForKeyword | SyntaxKind.FromKeyword | SyntaxKind.FunctionKeyword | SyntaxKind.GetKeyword | SyntaxKind.IfKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.ImportKeyword | SyntaxKind.InKeyword | SyntaxKind.InferKeyword | SyntaxKind.InstanceOfKeyword | SyntaxKind.InterfaceKeyword | SyntaxKind.IsKeyword | SyntaxKind.KeyOfKeyword | SyntaxKind.LetKeyword | SyntaxKind.ModuleKeyword | SyntaxKind.NamespaceKeyword | SyntaxKind.NeverKeyword | SyntaxKind.NewKeyword | SyntaxKind.NullKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.PackageKeyword | SyntaxKind.PrivateKeyword | SyntaxKind.ProtectedKeyword | SyntaxKind.PublicKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.RequireKeyword | SyntaxKind.GlobalKeyword | SyntaxKind.ReturnKeyword | SyntaxKind.SetKeyword | SyntaxKind.StaticKeyword | SyntaxKind.StringKeyword | SyntaxKind.SuperKeyword | SyntaxKind.SwitchKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.ThrowKeyword | SyntaxKind.TrueKeyword | SyntaxKind.TryKeyword | SyntaxKind.TypeKeyword | SyntaxKind.TypeOfKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.VarKeyword | SyntaxKind.VoidKeyword | SyntaxKind.WhileKeyword | SyntaxKind.WithKeyword | SyntaxKind.YieldKeyword | SyntaxKind.AsyncKeyword | SyntaxKind.AwaitKeyword | SyntaxKind.OfKeyword; type JsxTokenSyntaxKind = SyntaxKind.LessThanSlashToken | SyntaxKind.EndOfFileToken | SyntaxKind.ConflictMarkerTrivia | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.OpenBraceToken | SyntaxKind.LessThanToken; enum SyntaxKind { @@ -1581,6 +1581,9 @@ declare namespace ts { expression: Identifier | PropertyAccessEntityNameExpression; }; } + interface JSDocAuthorTag extends JSDocTag { + kind: SyntaxKind.JSDocAuthorTag; + } interface JSDocClassTag extends JSDocTag { kind: SyntaxKind.JSDocClassTag; } @@ -3521,6 +3524,7 @@ declare namespace ts { function isJSDocFunctionType(node: Node): node is JSDocFunctionType; function isJSDocVariadicType(node: Node): node is JSDocVariadicType; function isJSDoc(node: Node): node is JSDoc; + function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag; function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag; function isJSDocClassTag(node: Node): node is JSDocClassTag; function isJSDocEnumTag(node: Node): node is JSDocEnumTag; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index ab4faf036b..579b327618 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -72,7 +72,7 @@ declare namespace ts { pos: number; end: number; } - type JSDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.BacktickToken | SyntaxKind.Unknown | KeywordSyntaxKind; + type JSDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.GreaterThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.BacktickToken | SyntaxKind.Unknown | KeywordSyntaxKind; type KeywordSyntaxKind = SyntaxKind.AbstractKeyword | SyntaxKind.AnyKeyword | SyntaxKind.AsKeyword | SyntaxKind.BigIntKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.BreakKeyword | SyntaxKind.CaseKeyword | SyntaxKind.CatchKeyword | SyntaxKind.ClassKeyword | SyntaxKind.ContinueKeyword | SyntaxKind.ConstKeyword | SyntaxKind.ConstructorKeyword | SyntaxKind.DebuggerKeyword | SyntaxKind.DeclareKeyword | SyntaxKind.DefaultKeyword | SyntaxKind.DeleteKeyword | SyntaxKind.DoKeyword | SyntaxKind.ElseKeyword | SyntaxKind.EnumKeyword | SyntaxKind.ExportKeyword | SyntaxKind.ExtendsKeyword | SyntaxKind.FalseKeyword | SyntaxKind.FinallyKeyword | SyntaxKind.ForKeyword | SyntaxKind.FromKeyword | SyntaxKind.FunctionKeyword | SyntaxKind.GetKeyword | SyntaxKind.IfKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.ImportKeyword | SyntaxKind.InKeyword | SyntaxKind.InferKeyword | SyntaxKind.InstanceOfKeyword | SyntaxKind.InterfaceKeyword | SyntaxKind.IsKeyword | SyntaxKind.KeyOfKeyword | SyntaxKind.LetKeyword | SyntaxKind.ModuleKeyword | SyntaxKind.NamespaceKeyword | SyntaxKind.NeverKeyword | SyntaxKind.NewKeyword | SyntaxKind.NullKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.PackageKeyword | SyntaxKind.PrivateKeyword | SyntaxKind.ProtectedKeyword | SyntaxKind.PublicKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.RequireKeyword | SyntaxKind.GlobalKeyword | SyntaxKind.ReturnKeyword | SyntaxKind.SetKeyword | SyntaxKind.StaticKeyword | SyntaxKind.StringKeyword | SyntaxKind.SuperKeyword | SyntaxKind.SwitchKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.ThrowKeyword | SyntaxKind.TrueKeyword | SyntaxKind.TryKeyword | SyntaxKind.TypeKeyword | SyntaxKind.TypeOfKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.VarKeyword | SyntaxKind.VoidKeyword | SyntaxKind.WhileKeyword | SyntaxKind.WithKeyword | SyntaxKind.YieldKeyword | SyntaxKind.AsyncKeyword | SyntaxKind.AwaitKeyword | SyntaxKind.OfKeyword; type JsxTokenSyntaxKind = SyntaxKind.LessThanSlashToken | SyntaxKind.EndOfFileToken | SyntaxKind.ConflictMarkerTrivia | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.OpenBraceToken | SyntaxKind.LessThanToken; enum SyntaxKind { @@ -1581,6 +1581,9 @@ declare namespace ts { expression: Identifier | PropertyAccessEntityNameExpression; }; } + interface JSDocAuthorTag extends JSDocTag { + kind: SyntaxKind.JSDocAuthorTag; + } interface JSDocClassTag extends JSDocTag { kind: SyntaxKind.JSDocClassTag; } @@ -3521,6 +3524,7 @@ declare namespace ts { function isJSDocFunctionType(node: Node): node is JSDocFunctionType; function isJSDocVariadicType(node: Node): node is JSDocVariadicType; function isJSDoc(node: Node): node is JSDoc; + function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag; function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag; function isJSDocClassTag(node: Node): node is JSDocClassTag; function isJSDocEnumTag(node: Node): node is JSDocEnumTag; diff --git a/tests/baselines/reference/quickInfoJsDocTags.baseline b/tests/baselines/reference/quickInfoJsDocTags.baseline index d3ed4ad5ef..a146e8e187 100644 --- a/tests/baselines/reference/quickInfoJsDocTags.baseline +++ b/tests/baselines/reference/quickInfoJsDocTags.baseline @@ -2,13 +2,13 @@ { "marker": { "fileName": "/tests/cases/fourslash/quickInfoJsDocTags.ts", - "position": 256 + "position": 272 }, "quickInfo": { "kind": "function", "kindModifiers": "", "textSpan": { - "start": 256, + "start": 272, "length": 3 }, "displayParts": [ @@ -70,7 +70,7 @@ "tags": [ { "name": "author", - "text": "Me" + "text": "Me " }, { "name": "augments", diff --git a/tests/cases/fourslash/quickInfoJsDocTags.ts b/tests/cases/fourslash/quickInfoJsDocTags.ts index 798a850a31..2d81cb2367 100644 --- a/tests/cases/fourslash/quickInfoJsDocTags.ts +++ b/tests/cases/fourslash/quickInfoJsDocTags.ts @@ -3,7 +3,7 @@ // @Filename: quickInfoJsDocTags.ts /////** //// * Doc -//// * @author Me +//// * @author Me //// * @augments {C} Augments it //// * @template T A template //// * @type {number | string} A type