tsdoc icon indicating copy to clipboard operation
tsdoc copied to clipboard

tsdoc-unnecessary-backslash false positive

Open cowwoc opened this issue 2 years ago • 3 comments

Given the following description:

/**
 * <ul>
 * <li>Lines always end with <code>\n</code> or <code>\0</code>. The former denotes a newline. The latter
 * denotes the end of the string.</li>
 * </ul>
*/

tsdoc-unnecessary-backslash complains about \n and \0: tsdoc-unnecessary-backslash: A backslash can only be used to escape a punctuation character.

Expected behavior: the documentation should contain the literal string \n and \0.

cowwoc avatar Jul 17 '23 21:07 cowwoc

Can confirm this is still an issue.

peterflynn avatar May 05 '25 22:05 peterflynn

The TSDoc grammar does not give any special meaning to <code>. Instead, it treats it the same as any other HTML tag. Therefore according to the design, <code> will NOT disable Markdown expressions between those tags.

If you want a literal \ character, it would be done three different ways:

CommonMark code span:

/**
 * Lines always end with `\n` or `\0`.
 */

CommonMark backslash escape:

/**
 * Lines always end with <code>\\n</code> or <code>\\0</code>.
 */

HTML entity:

/**
 * Lines always end with <code>&#92;n</code> or <code>&#92;0</code>.
 */

Note that HTML entities were not implemented yet in the current TSDoc parser library, but we intended to support them.

Why is TSDoc designed that way?

Expected behavior: the documentation should contain the literal string \n and \0.

Your expectation comes from HTML, where \ doesn't have any special meaning. However TSDoc combines HTML with CommonMark-like syntax, where \ is an escape character. Actually, a CommonMark parser would not complain about your case either, because n has no special meaning, therefore CommonMark lieniently displays \n as a regular string.

But now consider this case:

/**
 * Lines always end with <code>\n</code>, i.e. using the escape character <code>\</code>.
 */

According to the grammar, the \ will undo the special meaning of </code>, causing catastrophic wrong parsing of this comment. A human reader would have trouble understanding why, because the lenient handling of \n wrongly suggests that \ is not an escape character.

CommonMark parsers usually don't worry about this because Markdown was designed for authors who can see an interactive preview of the output. If it's broken, they can just fiddle with the characters until it looks right.

By contrast, TSDoc was designed based on the idea that multiple different tools will try to parse your /** comment, often as part of some invisible backend that runs later, after your code is already merged. And because it's API code, TSDoc includes directives like @public that aren't just visual formatting -- if they are parsed incorrectly, it can break your API contracts. This is why TSDoc includes stricter checks, insisting on normalized forms that reduce the likelihood of mistakes.

octogonz avatar May 07 '25 01:05 octogonz

I no longer have this use-case so I'm fine either way, but for the sake of future users perhaps tsdoc-unnecessary-backslash should link to your explanation?

cowwoc avatar May 07 '25 02:05 cowwoc