-
Notifications
You must be signed in to change notification settings - Fork 131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Escaping doc comments inside doc comments #166
Comments
This isn't a TSDoc problem. It's a JavaScript problem. JavaScript (and therefore TypeScript) does not support nested block comments, so the whole comment ends at |
We could address this by providing an escaping mechanism like TSDoc escaping will need to depend heavily on context. This works against our goal that the rendered result should be predictable by a person who doesn't have access to an interactive renderer. For example, the most convenient rule is probably: "Inside a markdown code fence, every character is preserved literally except for |
This problem is fairly difficult. Users have a very strong expectation that a fenced code block is reproduced literally. For example, suppose we choose /**
* ```ts
* /**
* * Matches "abc\/def" or "*\\/abc" but not "C:\\foo\\bar"
* *\/
* function foo(path) {
* return /[a-z*]+\/[a-z]+$/.test(path);
* }
* ```
*/ If we allow But this means
It's highly confusing why the The |
I wonder if |
I thought of a possibly better solution to this problem! Suppose we have an API like this: function isDocComment(s: string): boolean {
return /^\/\*.*\*\/$/.test(s);
} ...and we want to show docs like this:
When we try to write TSDoc like this...
....we encounter a syntax error because JavaScript provides no mechanism for /**
* Returns `true` if `s` is enclosed in `/*` and `*
*+/`
* comment characters.
*
* @example
* ```ts
* // This prints "true":
* console.log(isDocComment("/** @public *
*+/"));
* ```
*/ The TSDoc parser would discard the newline and If you want to line it up horizontally for readability, maybe we could also allow multiple /**
* Returns `true` if `s` is enclosed in `/*` and `*
*+++++++++++++++++++++++++++++++++++++++++++++++++/`
* comment characters.
*
* @example
* ```ts
* // This prints "true":
* console.log(isDocComment("/** @public *
*++++++++++++++++++++++++++++++++++++++++/"));
* ```
*/ (The delimiter doesn't have to be What do you think? This seems better than the earlier proposals. |
I read your comment first, and then had to go back and read all the previous comments to be able to to understand what that escaping is actually doing. Of course, I'm not complaining about having to read, but I think this would be very difficult to understand. It's one of those things that comes up enough that it would need to be used every so often, but not often enough that anyone would have any idea what they're looking at when they see it. Is the only use case when you would ever use |
How would your approach represent this case? 🤓
|
It doesn't have to be a comment though; e.g. it could be a glob or RegExp with those characters. BTW this issue might also arise if someone is using |
This feature could also be used to wrap long lines, e.g. to satisfy an ESLint rule that limits line length.
|
Here's a poll where you can vote on the syntax: 🙂 https://twitter.com/octogonz_/status/1204589348525527040?s=19 |
@DanielRosenwasser, @sandersn: What do you think of this? If |
I wrote a comment before but deleted it because I misunderstood what you're asking. I don't know if we necessarily need to support this scenario - someone could just link to the spec page. Your escaping method does support this, but at the expense of being pretty difficult to read and write. Even your own example has a syntax error in it - it should be: /**
* Here is an example of how to escape `/
*+*` using TSDoc:
*
* ```ts
* /**
* * Returns `true` if `s` is enclosed in `/*` and `*
* *+/`
* * comment characters.
* *
* * @example
* * ```ts
* * // This prints "true":
* * console.log(isDocComment("/** @public *
* *+/"));
* * ```
* *
*+/
* ```
*/ |
I do think being able to break URLs is actually a more useful feature than being /**
* Add two numbers.
*
* @param a - the first number to add.
* @param b - the second number to add.
*
* @example Basic Usage
* ```ts
* add(123, 456); // -> 579;
* ```
* See it in action: [demo](http://www.typescriptlang.org/play/#code/GYVwdgxgLgl
*+g9mABAQwCaoBTIFyLCAWwCMBTAJwBpEjd9jyBKWw0sxAbwChEfEySoIMkmSIA1NQDcnAL6dOaTAEY
*+ATAGYqAFgCsANgaSgA).
*/ In this case I think the |
Another consideration - I don't think it would be an issue as long as the line-continuation behavior only occurs if there is no space before the character, but |
That could be an argument for |
By the way, we do plan to support HTML character entity references in TSDoc markdown. So instead of But Markdown does not allow this inside a code block. For example: /**
* In a future update to the TSDoc parser, this will get decoded: */
*
* ```
* const x = "*/"; // <--- this must be rendered as-is
* ```
*/ |
I was about to, but I think |
This seems like a lot of effort to work around a problem that could more readily be solved with "don't put /**
* ```js
* foo("/*comment*" + "/")
* foo("/*comment*\/")
* ```
*/ ESLint (and other linters) can usually be configured to ignore certain comments or URLs in comments that break the line-length rule, so supporting some sort of line-continuation character doesn't seem very compelling. |
For documentation generation purposes, you could always define a special |
Not sure how persuasive it is, but here's some samples of real world code that would have benefited from correctly encoding tsdoc/tsdoc/src/details/StandardTags.ts Lines 332 to 350 in 9e0c30a
rush-lib/src/cli/actions/InitAction.ts: // Matches a well-formed END macro ending a block section.
// Example: /*[END "DEMO"]*/
//
// Group #1 is the indentation spaces before the macro
// Group #2 is the section name
private static _endMacroRegExp: RegExp = /^(\s*)\/\*\[END "([A-Z]+)"\]\s*\*\/\s*$/; rush-lib/src/cli/actions/InitAction.ts: // "Block section" macros have this form:
//
// /*[BEGIN "NAME"]*/
// (content goes
// here)
// /*[END "NAME"]*/
//
And here's some .md files that just as easily could have been doc comments: ```javascript
var glob = require("glob")
// options is optional
glob("**/*.js", options, function (er, files) {
// files is an array of filenames.
// If the `nonull` option is set, and nothing
// was found, then files is ["**/*.js"]
// er is an error object or null.
})
``` eslint/docs/user-guide/command-line-interface.md: #### `--no-inline-config`
This option prevents inline comments like `/*eslint-disable*/` or
`/*global foo*/` from having any effect. This allows you to set an ESLint
config without files modifying it. All inline config comments are ignored, e.g.:
* `/*eslint-disable*/`
* `/*eslint-enable*/` (Note that |
As a counterpoint, maybe we could look for a real world instance of |
I use comments that span multiple lines in docblock comment code examples pretty often to show the result of a function call. It's inconvenient to not be able to use multi-line comments (using an escape). What I want: /**
Lorem ipsum.
```
foo();
/*
{
"x": 1,
"y": 2,
"z": 3
}
\*/
```
*/ (Using some kind of escape character. What I currently have to do: /**
Lorem ipsum.
```
foo();
// {
// "x": 1,
// "y": 2,
// "z": 3
// }
```
*/ Which looks more noisy and is more annoying to edit. |
I don't think @sindresorhus Your suggestion would require changing the ECMAScript grammar. Even if we could do that, the For example, instead of this: Nested escapes using /**
* Here is an example of how to escape `*
*+/` using TSDoc:
*
* ```ts
* /**
* * Returns `true` if `s` is enclosed in `/*` and `*
* *+/`
* * comment characters.
* *
* * @example
* * ```ts
* * // This prints "true":
* * console.log(isDocComment("/** @public *
* *+/"));
* *
* * // This is supposed to print a newline character:
* * console.log("\n");
* * ```
* *
*+/
* ```
*/ ...your approach would produce something like this: Nested escapes using
I'm becoming increasingly convinced that @rbuckton's suggestion of "find ways to avoid saying Voldemort" is a close second, though. 😊 |
@octogonz |
Another possibility (somewhat of an extension of the 'Voldemort' option) would be to recommend to use some sort of Unicode hack to just never have that |
@iansan5653 With arbitrary hidden or look-alike characters, the code snippets will fail to run when they are extracted and ran by some documentation tooling that looks for code blocks and converts them into live examples (f.e. places the snippet in a |
This problem is the one thing that makes me want to switch to But the |
I've been wrestling with this problem with JSDoc for years, both from the side as a user trying to document things, and as the creator of
Here are a few common situations where you need to use
For https://github.com/jaydenseric/jsdoc-md/blob/v9.1.1/private/unescapeJsdoc.js#L3-L24 Edit: Updated function: https://github.com/jaydenseric/jsdoc-md/blob/c37795fa1976e17aeb4acce1832795efefa093c9/unescapeJsdoc.mjs#L1-L22 There are problems with this convention though, unless the wider ecosystem adopts it. Firstly, VS Code displays the code example with the escape still there in intellisense tooltips: Secondly, I haven't figured out yet how to get the |
Is this TSDoc specific? Because in JSDoc, there is no such stated requirement except that whitespace must follow the initial It seems the TypeScript playground is respecting |
Did anyone consider allowing and filtering out Zero-width space - Wikipedia? Drawback: It is invisible. Example: /**
* @param pattern glob pattern
* @param nested when true add `**/<glob>/**`
^^ zero-width space between * and /
* @returns the set of matching files.
*/ If tsdoc filtered out the zero-width space, then examples become useful. |
Imagine that authors of a library want to write a glob pattern inside of a JSDoc comment, like this: export interface ExtendableSettings extends Settings {
/**
* Overrides are used to apply settings for specific files in your project.
*
* For example:
*
* ```javascript
* "overrides": [
* // Force `*.hrr` and `*.crr` files to be treated as `cpp` files:
* {
* "filename": "**/{*.hrr,*.crr}",
* "languageId": "cpp"
* },
* // Force `*.txt` to use the Dutch dictionary (Dutch dictionary needs to be installed separately):
* {
* "language": "nl",
* "filename": "**/dutch/**/.txt"
* }
* ]
* ```
*/
overrides?: OverrideSettings[];
} In this hypothetical, the author wants to show an example configuration file for end-users to copy paste into their own configuration files. This JSDoc is valid, because I am using the zero-width space technique described above. But in this case, would a zero-width space space mess up the glob parser? If it does, that will be terrible UX for the end-user. They will have an invalid glob pattern, and it will inextricably fail. But then, in their exasperation, when they re-type the glob pattern from scratch using the exact same characters, it will work just fine. =p |
Came across this issue today... Feels like a WONTFIX, but just wanted to note a solution that I expected might work but didn't... Djot (a Markdown alternative) has an interesting solution to escaping that it uses for its code blocks: You can use three or more backticks. This allows you to escape ``` inside a code block:
It occurred to me that a similar solution would work here. So if this is a normal TSDoc comment...
... then you could do something like this to escape a nested comment:
And then potentially you could go even deeper to escape the escaped comments, if you really wanted to:
Seems like that would be a pretty complete solution. |
The real issue is that the JavaScript / TypeScript compiler interprets the nested The question in this issue is how to represent a |
The problem is that this would require a breaking change to the ECMAScript grammar, which would not be backwards compatible with legacy scripts. It's a good idea, but outside the scope of the TSDoc specification.
The Nonetheless, if a company had a large monorepo and decided that they would prefer to switch to |
It's useful to users to include code examples in documentation comments. Sometimes you need to illustrate what the output of different code examples are, so you put it in a comment below, and if it's multiple lines, you use a block comment. The problem is that TSDoc doesn't correctly parse this:
I think it should handle block comments when they're inside a code block in the documentation comment.
The text was updated successfully, but these errors were encountered: