Skip to content

JSDoc comments separated by white-space should not be combined #32062

@rjgotten

Description

@rjgotten

TypeScript Version: (Whatever is current with VSCode 1.35.1)

Search Terms: JSDoc combining comments

Code:

/**
 * @typedef {Object} Foo
 */

/**
 * @typedef {Object} Bar
 */

/**
 * Description goes here
 */
export default class Baz {
}

Expected behavior:
Documentation for Baz does not include information from JSDoc islets that are not connected to the class definition.

Actual behavior:
Documentation for Baz includes information from earlier JSDoc islets that are not connected to the class definition.

Related Issues:
#15106
#19537
#41811 (vscode)
(And possibly a lot of others)

Possible workarounds:

  1. Place comments that are not attached to code artifacts, such as @typedef, at the bottom of the file.
  2. Place those comments into separate files and use {import("")} typings.
  3. Insert dummy code lines inbetween those comments and the code such as void 0; to force the TypeScript compiler to treat them in isolation.

I understand that others have closed this type of issue before as a won't fix, for instance because:

@mhegazy
this is how the comment system is built. changing that would not be simple,

or:

@mjbvz
This is a limitation of how our JS Doc support is designed. JSDoc comments are merged into the next declaration

I am re-filing this issue again, but with reason to doubt the above.

The decision to treat this "as designed" makes no sense. Clearly it is broken - as in delivering a broken user experience for JSDoc users. And one which runs counter to practically any other sane JSDoc or JSDoc-like parser on market. Microsoft should pave the cowpath here and follow existing convention, not drop back into old misbehavior and towing their own line.

I doubt that - as prior quoted - this "would not be simple" in the sense of requiring large amounts of code to be adapted. Or that there is a hard "limitation" somehow at play in the parser.

The core problem here seems that when parsing JSDoc comments attached to nodes, the entire range of leading comment blocks is processed, using - eventually - the scanner.ts file's getLeadingCommentRanges function, which calls into the reduceEachLeadingCommentRange function.

I.e.

function addJSDocComment<T extends HasJSDoc>(node: T): T {
Debug.assert(!node.jsDoc); // Should only be called once per node
const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceFile.text), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos));
if (jsDoc.length) node.jsDoc = jsDoc;
return node;
}

export function getJSDocCommentRanges(node: Node, text: string) {
const commentRanges = (node.kind === SyntaxKind.Parameter ||
node.kind === SyntaxKind.TypeParameter ||
node.kind === SyntaxKind.FunctionExpression ||
node.kind === SyntaxKind.ArrowFunction ||
node.kind === SyntaxKind.ParenthesizedExpression) ?
concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) :
getLeadingCommentRanges(text, node.pos);
// True if the comment starts with '/**' but not if it is '/**/'
return filter(commentRanges, comment =>
text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk &&
text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash);
}

export function getLeadingCommentRanges(text: string, pos: number): CommentRange[] | undefined {
return reduceEachLeadingCommentRange(text, pos, appendCommentRange, /*state*/ undefined, /*initial*/ undefined);
}

The reduceEachLeadingCommentRange combines all preceding comments, also those separated from the code by lines of white-space. A simple fix for this JSDoc parsing bug would be to not do this and to instead ignore comments that are separated from the declaring node by one or more lines of whitespace.

This requires either:

  1. a separate implementation which traverses bottom-to-top through the comment blocks and halts at the first line of white-space; or
  2. a switch/flag on the existing function to trigger aforementioned alternate behavior.

Even a more simple and less performant implementation which simply discards disconnected comments after they've already been parsed would atleast be functional. (And have no worse performance than current.)

Either way, it seems to not quite be rocket-science. So why this problem has been marked as "won't fix" / "as designed" before is beyond me.

If there's a particularly hard component here to fix that I am missing, then please also consider this bug report a request to illustrate where that would be, as this was not disclosed when any of the previous issues were filed and - wrongfully, imho - closed.

Thank you.

Metadata

Metadata

Assignees

Labels

FixedA PR has been merged for this issueSuggestionAn idea for TypeScript

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions