diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5dcfb5ee075..b3ae9b9f7b6 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -7740,63 +7740,31 @@ namespace ts { } function parseAuthorTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocAuthorTag { - const authorInfoWithEmail = tryParse(() => tryParseAuthorNameAndEmail()); - if (!authorInfoWithEmail) { - const end = getNodePos(); - return finishNode(factory.createJSDocAuthorTag(tagName, parseTrailingTagComments(start, end, indent, indentText)), start, end); - } - - let comments = authorInfoWithEmail; - if (lookAhead(() => nextToken() !== SyntaxKind.NewLineTrivia)) { - const comment = parseTagComments(indent); - if (comment) { - comments += comment; - } - } - - return finishNode(factory.createJSDocAuthorTag(tagName, comments), start); + const comments = parseAuthorNameAndEmail() + (parseTrailingTagComments(start, end, indent, indentText) || ""); + return finishNode(factory.createJSDocAuthorTag(tagName, comments || undefined), start); } - function tryParseAuthorNameAndEmail(): string | undefined { + function parseAuthorNameAndEmail(): string { const comments: string[] = []; - let seenLessThan = false; - let seenGreaterThan = false; + let inEmail = false; let token = scanner.getToken(); - - loop: while (true) { - switch (token) { - case SyntaxKind.Identifier: - case SyntaxKind.WhitespaceTrivia: - case SyntaxKind.DotToken: - case SyntaxKind.AtToken: - comments.push(scanner.getTokenText()); - break; - case SyntaxKind.LessThanToken: - if (seenLessThan || seenGreaterThan) { - return; - } - seenLessThan = true; - comments.push(scanner.getTokenText()); - break; - case SyntaxKind.GreaterThanToken: - if (!seenLessThan || seenGreaterThan) { - return; - } - seenGreaterThan = true; - comments.push(scanner.getTokenText()); - scanner.setTextPos(scanner.getTokenPos() + 1); - break loop; - case SyntaxKind.NewLineTrivia: - case SyntaxKind.EndOfFileToken: - break loop; + while (token !== SyntaxKind.EndOfFileToken && token !== SyntaxKind.NewLineTrivia) { + if (token === SyntaxKind.LessThanToken) { + inEmail = true; } - + else if (token === SyntaxKind.AtToken && !inEmail) { + break; + } + else if (token === SyntaxKind.GreaterThanToken && inEmail) { + comments.push(scanner.getTokenText()); + scanner.setTextPos(scanner.getTokenPos() + 1); + break; + } + comments.push(scanner.getTokenText()); token = nextTokenJSDoc(); } - if (seenLessThan && seenGreaterThan) { - return comments.length === 0 ? undefined : comments.join(""); - } + return comments.join(""); } function parseImplementsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImplementsTag { diff --git a/src/testRunner/unittests/jsDocParsing.ts b/src/testRunner/unittests/jsDocParsing.ts index 87840865067..a2f5037be2a 100644 --- a/src/testRunner/unittests/jsDocParsing.ts +++ b/src/testRunner/unittests/jsDocParsing.ts @@ -319,6 +319,21 @@ namespace ts { `/** * @author John Doe * @author John Doe unexpected comment + * @author 108 <108@actionbutton.net> Video Games Forever + * @author Multiple Ats + * @author Multiple Open Carets + * @author Multiple Close Carets invalid>but>who>cares> + * @author Unclosed Carets @author Line + * @author @author @author Empty authors + * @author + * @author + * Comments + * @author Early Close Caret > + * @author No Line Breaks: + * must be on the same line to parse + * @author Long Comment I + * want to keep commenting down here, I dunno. */`); parsesCorrectly("consecutive newline tokens", diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.authorTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.authorTag.json index b9e91293d73..9ab0162e2a8 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.authorTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.authorTag.json @@ -1,7 +1,7 @@ { "kind": "JSDocComment", "pos": 0, - "end": 112, + "end": 738, "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 0, @@ -25,7 +25,7 @@ "1": { "kind": "JSDocAuthorTag", "pos": 50, - "end": 110, + "end": 112, "modifierFlagsCache": 0, "transformFlags": 0, "tagName": { @@ -38,9 +38,278 @@ }, "comment": "John Doe unexpected comment" }, - "length": 2, + "2": { + "kind": "JSDocAuthorTag", + "pos": 112, + "end": 170, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 113, + "end": 119, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + }, + "comment": "108 <108@actionbutton.net> Video Games Forever" + }, + "3": { + "kind": "JSDocAuthorTag", + "pos": 170, + "end": 227, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 171, + "end": 177, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + }, + "comment": "Multiple Ats " + }, + "4": { + "kind": "JSDocAuthorTag", + "pos": 227, + "end": 272, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 228, + "end": 234, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + }, + "comment": "Multiple Open Carets " + }, + "5": { + "kind": "JSDocAuthorTag", + "pos": 272, + "end": 338, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 273, + "end": 279, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + }, + "comment": "Multiple Close Carets invalid>but>who>cares>" + }, + "6": { + "kind": "JSDocAuthorTag", + "pos": 338, + "end": 381, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 339, + "end": 345, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + }, + "comment": "Unclosed Carets " + }, + "9": { + "kind": "JSDocAuthorTag", + "pos": 429, + "end": 445, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 430, + "end": 436, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + }, + "comment": "Line" + }, + "10": { + "kind": "JSDocAuthorTag", + "pos": 445, + "end": 453, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 446, + "end": 452, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + } + }, + "11": { + "kind": "JSDocAuthorTag", + "pos": 453, + "end": 461, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 454, + "end": 460, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + } + }, + "12": { + "kind": "JSDocAuthorTag", + "pos": 461, + "end": 486, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 462, + "end": 468, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + }, + "comment": "Empty authors" + }, + "13": { + "kind": "JSDocAuthorTag", + "pos": 486, + "end": 497, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 487, + "end": 493, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + } + }, + "14": { + "kind": "JSDocAuthorTag", + "pos": 497, + "end": 522, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 498, + "end": 504, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + }, + "comment": "Comments" + }, + "15": { + "kind": "JSDocAuthorTag", + "pos": 522, + "end": 559, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 523, + "end": 529, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + }, + "comment": "Early Close Caret > " + }, + "16": { + "kind": "JSDocAuthorTag", + "pos": 559, + "end": 598, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 560, + "end": 566, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + }, + "comment": "No Line Breaks: must be on the same line to parse" + }, + "18": { + "kind": "JSDocAuthorTag", + "pos": 645, + "end": 736, + "modifierFlagsCache": 0, + "transformFlags": 0, + "tagName": { + "kind": "Identifier", + "pos": 646, + "end": 652, + "modifierFlagsCache": 0, + "transformFlags": 0, + "escapedText": "author" + }, + "comment": "Long Comment I\nwant to keep commenting down here, I dunno." + }, + "length": 19, "pos": 7, - "end": 110, + "end": 736, "hasTrailingComma": false, "transformFlags": 0 }