TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

TypeScript class method decorator not rendering properly in version >= 1.63.2

Open dreamorosi opened this issue 3 years ago • 20 comments

Does this issue occur when all extensions are disabled?: Yes

  • VS Code Version: 1.63.2
  • OS Version: Darwin x64 20.6.0

Steps to Reproduce:

  1. Write a JSDoc string with an example that involves a decorator:
class MyClass {
   /**
   * This is an example of a decorator.
   * 
   * @example
   * ```typescript
   * import { MyClass } from '@org/myClass';
   * 
   * const myClass = new MyClass();
   * 
   * class MyAwesomeClass {
   *   @myClass.decorateMethod()
   *   public doStuff() {
   *     ...
   *   }
   * }
   * 
   * ```
   * 
   * @decorator Class
   */
   public decorateMethod(): MyType {
     return (target, _propertyKey, descriptor) => {
       const originalMethod = descriptor.value;

       descriptor.value = ((event, context, callback) => {
         return originalMethod?.apply(target, [ event, context, callback ]);
       });

       return descriptor;
     };
   }
}
  1. Use decorator / hover on method declaration:

image

As you can see from the screenshot above the example appears not to be rendered correctly with two main issues:

  • Decorator is rendered on a new line & wrapped with *
  • All code indentation after the decorator is lost

Before opening this issue I've searched the repo (& the TypeScript one) and found a series of other issues. Most of them have been closed as duplicates or as fixed but as the above shows the issue is still there. Examples:

  • https://github.com/microsoft/TypeScript/issues/39371
  • https://github.com/microsoft/TypeScript/issues/38922
  • https://github.com/microsoft/vscode/issues/119218
  • https://github.com/microsoft/TypeScript/pull/42364

If the issue has been indeed fixed, could you please take a second to clarify what's the intended usage to allow VS Code to render decorators correctly? I'm aware that decorators are an experimental feature, if that's the reason why this is not supported could you please state it?

Thanks in advance.

dreamorosi avatar Jan 31 '22 10:01 dreamorosi

Looks like a duplicate of https://github.com/microsoft/TypeScript/issues/35310 but let's wait for feedback from the TS team

mjbvz avatar Feb 01 '22 00:02 mjbvz

None of the workarounds suggested in that issue work as it's also reported by other users in that same issue.

It was marked as "work as intended", does it mean that decorators are not supposed to be rendered correctly?

dreamorosi avatar Feb 01 '22 08:02 dreamorosi

Since this was rescheduled/left out of the last two iterations, is there any chance that this can be added to the TypeScript 4.9.0 one?

dreamorosi avatar Aug 26 '22 07:08 dreamorosi

Looking at the parser, the problem is that backticks don't persist across lines, even triple backticks.

sandersn avatar Sep 06 '22 18:09 sandersn

A naive change to stop resetting the backtick parsing does stop treating @myClass as a tag, but also stops maintaining the indent margin and skipping leading asterisks. That needs to be maintained, even when parsing backtick-quoted text.

sandersn avatar Sep 06 '22 19:09 sandersn

Update: the fix at #50677 correctly makes single and triple backticks multiline, but this breaks unclosed backticks in the tests and would break them in the compiler source code itself. We're discussing whether to take the change or not.

sandersn avatar Sep 12 '22 17:09 sandersn

\` for single back ticks perhaps.

I don't think I've ever used or seen a single back tick anywhere, so a very few minority of people (if they even exist) can migrate.

trusktr avatar Oct 01 '22 16:10 trusktr

I think a solution should work with both code fences, and @example blocks.

Personally I think GitHub has the best handling of back ticks. Might be worth looking at.

But if back ticks can't be fixed, I think at least \@ inside of an @example block (or anywhere) should just display @ as a single character.

Another option for escaping @ could be to write one double: @@.

JSDoc was designed before the language had decorators, so I think anything goes here really.

trusktr avatar Oct 01 '22 16:10 trusktr

better-docs is a sweet JSDoc parser and generator for TypeScript, backward compatible with the original JSDoc.

https://github.com/SoftwareBrothers/better-docs

@wojtek-krysiak do you have any thoughts on how to handle decorators?

I think it would make sense to ensure that TypeScript's format aligns well with the best tools in the community (like better-docs).

Better docs is great because it takes TypeScript code (with JSDoc) and can output 100% actual-JSDoc compatible JSDoc comments for compatibility with official JSDoc tooling, whereas other tools like TSDoc are not compatible.

trusktr avatar Oct 01 '22 17:10 trusktr

JSDoc itself is still active, and the community has open issues for this:

https://github.com/jsdoc/jsdoc/issues/1521 https://github.com/jsdoc2md/jsdoc-to-markdown/issues/209

@hegemonic do you have any opinions on decorator support?

I believe we should all aim to be on the same page to avoid community fracture. It would be so much better to coalesce into a common future.

In the worst case, a tool like better-docs would have to take incompatible syntax and convert it to compatible syntax, which wouldn't be ideal.

trusktr avatar Oct 01 '22 17:10 trusktr

Hi everyone, any chance to get this addressed as part of the 5.0 milestone?

dreamorosi avatar Nov 19 '22 11:11 dreamorosi

Any progress on the code indentation portion of this issue?

HiEv avatar Aug 11 '23 21:08 HiEv

Decorators are non-experimental now with TypeScript 5. Can we have this fix soon pleeease? 🙏

trusktr avatar Sep 25 '23 19:09 trusktr

This is really stupid and bad, but I use invisible separator U+2063 "⁣" before "@" as workaround and it works fine.

image

rmnilin avatar Oct 16 '23 07:10 rmnilin

@rnln I tried your suggestion, but that causes weird formatting for me:

Screenshot 2023-11-20 at 1 17 03 PM

For now, this is what I've settled with my docs looking like:

Screenshot 2023-11-20 at 1 13 52 PM

(note, replace double ampersands with one ampersand)

🤣

trusktr avatar Nov 20 '23 21:11 trusktr

@trusktr It's odd because I tried adding this invisible character to your documentation and it worked for me.

Screenshot image

After that, I took the liberty of adjusting the indentation, using @example instead of ```.

Screenshot image

This is just an example and I'm not sure it will be of help, but here's a snippet just in case:

Snippet
/**
 * @class Effectful -
 *
 * `mixin`
 *
 * Create Solid.js effects using `this.createEffect(fn)` and easily stop them
 * all by calling `this.stopEffects()`.
 *
 * @example
 * import {element, Effectful} from 'lume'
 *
 * ⁣@element('my-element')
 * class MyElement extends Effectful(HTMLElement) {
 *   ⁣@attribute foo = "foo"
 *   ⁣@attribute bar = "bar"
 *
 *   connectedCallback() {
 *     // Log `foo` and `bar` any time either of them change.
 *     this.createEffect(() => {
 *       console.log('foo, bar:', this.foo, this.bar)
 *     })
 *
 *     // Log only `bar` any time it changes.
 *     this.createEffect(() => {
 *       console.log('bar:', this.bar)
 *     })
 *   }
 *
 *   disconnectedCallback() {
 *     // Stop both of the effects.
 *     this.stopEffects()
 *   }
 * }
 */

rmnilin avatar Nov 21 '23 16:11 rmnilin

That snippet is working for me now. Not sure why I wasn't able to get it working before. EDIT: Ah, I was putting the invisible non-space after the @, not before the @.

Also, weird, I thought indentation when using code fences worked before (might be mis-recalling, and here's a bug report for that), but I do see it is currently broken. Unfortunately I have to keep the code fences for now because those JSDocs get consumed and rendered as markdown, f.e. the content here is from JSDoc tags:

https://docs.lume.io/api/utils/Settable

Source:

https://github.com/lume/lume/blob/develop/src/utils/Settable.ts#L5

But perhaps I can update the JSDoc extractor to support @example. How do we use multiple @example blocks with non-code content (f.e. a paragraph) between each example like we can with code fences under a single JSDoc tag? Doesn't seem possible.

trusktr avatar Nov 29 '23 06:11 trusktr

@rnln nice trick! <3 It didn't work for me, but it gave me a clue about the symbol "U+2064" (invisible plus). It's still a hack, but it's working :)

VSCode

2024-01-19_10-46

Jetbarins IDEA

2024-01-19_10-47

Memoraike avatar Jan 19 '24 10:01 Memoraike

Any plan for this?

kasir-barati avatar Apr 15 '25 12:04 kasir-barati

This issue affects not only decorators with TS type, but also when using @example code blocks that show code that uses @, e.g. Angular or Svelte (I think?):

/**
 * @example
 *
 * ```html
 * ⁣@for (item of items track item) {
 *   <div>{{ item.name }}</div>
 * }
 * ```
 */
export class Foo {}

Image

It's not very intuitive to need to fix this by finding and copy pasting a invisible separator U+2063 right before the @ to get correct formatting. I really think when inside a code block (e.g. ```js or html/ts/etc), that the @ should not be treated as a JSDoc tag.

csvn avatar Jun 17 '25 16:06 csvn

Affects the Angular jsdoc too :\

Image

Image

TheKoTech avatar Jul 03 '25 11:07 TheKoTech

Perhaps this is a bit naive, but since markdown parsing is intrinsically complex, maybe we could consider the good old heredoc operator?

/**
 * @example << EOF
 * // ...
 * EOF
 */

I think the likelihood of things being broken for anyone will be pretty close to zero.

apendua avatar Nov 05 '25 22:11 apendua

Perhaps this is a bit naive, but since markdown parsing is intrinsically complex, maybe we could consider the good old heredoc operator?

Adding another type of syntax would just complicate things more. Also Markdown code fences are essentially a type of heredoc syntax already, in that the end tag must match the start tag. It's just that instead of word strings like EOF/HERE, the tag is 3 or more of ` or ~, followed by an annotation (optional) + newline for the start tag, and newline/eof for the end tag.

lionel-rowe avatar Nov 06 '25 02:11 lionel-rowe

I see. I guess the key differentiator here is the presence of "<<", which helps in resolving the ambiguity and keeping backwards correctness. Of course anyone could use triple backticks instead of EOF.

apendua avatar Nov 06 '25 06:11 apendua

I see. I guess the key differentiator here is the presence of "<<", which helps in resolving the ambiguity and keeping backwards correctness. Of course anyone could use triple backticks instead of EOF.

The underlying bug is related to @ though, not ` or <<. Without fixing the parsing of multiline JSDoc tags, << EOF\n@\nEOF would suffer exactly the same problem as ```\n@\n```.

lionel-rowe avatar Nov 06 '25 06:11 lionel-rowe

If I am reading correctly, there has already been an attempt to implement "vanilla" markdown experience:

https://github.com/microsoft/TypeScript/issues/47679#issuecomment-1244077572

but it was rejected because it could break existing JSDoc comments with unbalanced backticks.

So it's not really the lack of multiline parsing, which can be easily added, that is blocking us here but the fact that there's no consensus about what syntax to use.

apendua avatar Nov 06 '25 06:11 apendua