JSDoc comment parsing supports multiline backticks

Previously, backticks in JSDoc ended at the end of a line. This PR
changes that so that backticks continue parsing until another backtick.

Note that triple backticks and single backticks are treated the same
way. The change is already very clunky, and I haven't thought about how
much clunkier it would be to track backtick history in the parser.
This commit is contained in:
Nathan Shively-Sanders
2022-09-07 11:45:40 -07:00
parent b58721fe15
commit 795c53a786
6 changed files with 102 additions and 12 deletions
+18 -5
View File
@@ -8123,6 +8123,8 @@ namespace ts {
SawAsterisk,
SavingComments,
SavingBackticks, // NOTE: Only used when parsing tag comments
SavingBackticksBeginningOfLine,
SavingBackticksSawAsterisk,
}
const enum PropertyLikeParse {
@@ -8433,13 +8435,13 @@ namespace ts {
loop: while (true) {
switch (tok) {
case SyntaxKind.NewLineTrivia:
state = JSDocState.BeginningOfLine;
state = (state as JSDocState) === JSDocState.SavingBackticks || (state as JSDocState) === JSDocState.SavingBackticksBeginningOfLine || (state as JSDocState) === JSDocState.SavingBackticksSawAsterisk ? JSDocState.SavingBackticksBeginningOfLine : JSDocState.BeginningOfLine;
// don't use pushComment here because we want to keep the margin unchanged
comments.push(scanner.getTokenText());
indent = 0;
break;
case SyntaxKind.AtToken:
if (state === JSDocState.SavingBackticks
if (state === JSDocState.SavingBackticks || state === JSDocState.SavingBackticksBeginningOfLine || state === JSDocState.SavingBackticksSawAsterisk
|| state === JSDocState.SavingComments && (!previousWhitespace || lookAhead(isNextJSDocTokenWhitespace))) {
// @ doesn't start a new tag inside ``, and inside a comment, only after whitespace or not before whitespace
comments.push(scanner.getTokenText());
@@ -8464,7 +8466,7 @@ namespace ts {
}
break;
case SyntaxKind.OpenBraceToken:
state = JSDocState.SavingComments;
state = (state as JSDocState) === JSDocState.SavingBackticks || (state as JSDocState) === JSDocState.SavingBackticksBeginningOfLine || (state as JSDocState) === JSDocState.SavingBackticksSawAsterisk ? JSDocState.SavingBackticks : JSDocState.SavingComments;
const commentEnd = scanner.getStartPos();
const linkStart = scanner.getTextPos() - 1;
const link = parseJSDocLink(linkStart);
@@ -8479,7 +8481,7 @@ namespace ts {
}
break;
case SyntaxKind.BacktickToken:
if (state === JSDocState.SavingBackticks) {
if (state === JSDocState.SavingBackticks || state === JSDocState.SavingBackticksBeginningOfLine || state === JSDocState.SavingBackticksSawAsterisk) {
state = JSDocState.SavingComments;
}
else {
@@ -8494,11 +8496,22 @@ namespace ts {
indent += 1;
break;
}
if (state === JSDocState.SavingBackticksBeginningOfLine) {
// leading asterisks start recording on the *next* (non-whitespace) token
state = JSDocState.SavingBackticksSawAsterisk;
indent += 1;
break;
}
// record the * as a comment
// falls through
default:
if (state !== JSDocState.SavingBackticks) {
state = JSDocState.SavingComments; // leading identifiers start recording as well
if (state === JSDocState.SavingBackticksBeginningOfLine || state === JSDocState.SavingBackticksSawAsterisk) {
state = JSDocState.SavingBackticks
}
else {
state = JSDocState.SavingComments; // leading identifiers start recording as well
}
}
pushComment(scanner.getTokenText());
break;
@@ -0,0 +1,31 @@
tests/cases/conformance/jsdoc/jsdocParseMatchingBackticks.js(22,22): error TS7006: Parameter 'gamma' implicitly has an 'any' type.
==== tests/cases/conformance/jsdoc/jsdocParseMatchingBackticks.js (1 errors) ====
/**
* `@param` initial at-param is OK in title comment
* @param {string} x hi there `@param`
* @param {string} y hi there @ * param
* this is the margin
* so we'll drop everything before it
`@param` @param {string} z hello???
* `@param` @param {string} alpha hello???
* `@ * param` @param {string} beta hello???
* @param {string} gamma
*/
export function f(x, y, z, alpha, beta, gamma) {
return x + y + z + alpha + beta + gamma
}
/**
* Unmatched backticks keep going past newlines
* @param {string} y hi there `@ * param
* this is the margin
* so we'll drop everything before it
* @param {string} gamma
*/
export function g(y, gamma) {
~~~~~
!!! error TS7006: Parameter 'gamma' implicitly has an 'any' type.
return y + gamma
}
@@ -2,7 +2,7 @@
/**
* `@param` initial at-param is OK in title comment
* @param {string} x hi there `@param`
* @param {string} y hi there `@ * param
* @param {string} y hi there @ * param
* this is the margin
* so we'll drop everything before it
`@param` @param {string} z hello???
@@ -27,4 +27,20 @@ export function f(x, y, z, alpha, beta, gamma) {
>beta : Symbol(beta, Decl(jsdocParseMatchingBackticks.js, 11, 33))
>gamma : Symbol(gamma, Decl(jsdocParseMatchingBackticks.js, 11, 39))
}
/**
* Unmatched backticks keep going past newlines
* @param {string} y hi there `@ * param
* this is the margin
* so we'll drop everything before it
* @param {string} gamma
*/
export function g(y, gamma) {
>g : Symbol(g, Decl(jsdocParseMatchingBackticks.js, 13, 1))
>y : Symbol(y, Decl(jsdocParseMatchingBackticks.js, 21, 18))
>gamma : Symbol(gamma, Decl(jsdocParseMatchingBackticks.js, 21, 20))
return y + gamma
>y : Symbol(y, Decl(jsdocParseMatchingBackticks.js, 21, 18))
>gamma : Symbol(gamma, Decl(jsdocParseMatchingBackticks.js, 21, 20))
}
@@ -2,7 +2,7 @@
/**
* `@param` initial at-param is OK in title comment
* @param {string} x hi there `@param`
* @param {string} y hi there `@ * param
* @param {string} y hi there @ * param
* this is the margin
* so we'll drop everything before it
`@param` @param {string} z hello???
@@ -32,4 +32,21 @@ export function f(x, y, z, alpha, beta, gamma) {
>beta : string
>gamma : string
}
/**
* Unmatched backticks keep going past newlines
* @param {string} y hi there `@ * param
* this is the margin
* so we'll drop everything before it
* @param {string} gamma
*/
export function g(y, gamma) {
>g : (y: string, gamma: any) => string
>y : string
>gamma : any
return y + gamma
>y + gamma : string
>y : string
>gamma : any
}
@@ -7,7 +7,7 @@
/**
* `@param` initial at-param is OK in title comment
* @param {string} x hi there `@param`
* @param {string} y hi there `@ * param
* @param {string} y hi there @ * param
* this is the margin
* so we'll drop everything before it
`@param` @param {string} z hello???
@@ -18,3 +18,13 @@
export function f(x, y, z, alpha, beta, gamma) {
return x + y + z + alpha + beta + gamma
}
/**
* Unmatched backticks keep going past newlines
* @param {string} y hi there `@ * param
* this is the margin
* so we'll drop everything before it
* @param {string} gamma
*/
export function g(y, gamma) {
return y + gamma
}
@@ -11,15 +11,18 @@
//// * @param {string} x hi there `@param`
//// * @param {string} y hi there `@ * param
//// * this is the margin
//// * @param {string} z OOPS, unclosed backtick!
//// */
////export function f(x, y) {
//// return x/*x*/ + y/*y*/
////export function f(x, y, z) {
//// return x/*x*/ + y/*y*/ + z/*z*/
////}
////f/*f*/
goTo.marker("f");
verify.quickInfoIs("function f(x: string, y: string): string", "`@param` initial at-param is OK in title comment");
verify.quickInfoIs("function f(x: string, y: string, z: any): string", "`@param` initial at-param is OK in title comment");
goTo.marker("x");
verify.quickInfoIs("(parameter) x: string", "hi there `@param`");
goTo.marker("y");
verify.quickInfoIs("(parameter) y: string", "hi there `@ * param\nthis is the margin");
verify.quickInfoIs("(parameter) y: string", "hi there `@ * param\nthis is the margin\n@param {string} z OOPS, unclosed backtick!");
goTo.marker("z");
verify.quickInfoIs("(parameter) z: any", undefined);