GeezerVison is showing github.com — Editor support for @see and {@link} in JSDoc comments tags · Issue #35524 · microsoft/TypeScript
Editor support for @see and {@link} in JSDoc comments tags #35524DescriptionSearch Terms
jsdoc @link
jsdoc @see
jsdoc @see @link
Suggestion
Reminder of what {@link} does
Whenever a {@link} tag is encountered in JSDoc, it’d be nice to have it formatted as an actual anchor. It works with URL and symbols relative to the documented one: a function, a property of the current class, or a function in another class?
The @see tag can also reference a symbol without any {@link}, provided there is only a path to a symbol and no free-form text next to it. https://jsdoc.app/tags-see.html
Use Cases
I often speak of other functions/classes in my doc comments, and as {@link} is described on JSDoc’s website, it’d be nice to have it parsed by the langage server and have it shown as a clickable link in any compatible doc widget.
Examples
import { Blah } from "./blah";
/**
* This won’t work due to scope: {@link baz}
* This will: {@link Foo#baz}
*
*
* The @see annotation can reference symbols as well, as stated on
* {@link https://jsdoc.app/tags-see.html JSDoc’s website}
* @see Document
*/
class Foo<T> {
/** I want a link to {@link bar}. */
private baz: T;
/** But I can also reference {@link Foo | the parent class}. */
public bar(): T {
return this.baz;
}
/** @deprecated please use {@link Blah#grog} instead. */
public grog(): void {}
/** What to do with this link? {@link mysterySymbol} */
public grug(): void {}
}
Non-imported symbols
A question that subsists is “what to do when {Link (@link)} refers to a symbol that exists in the project but isn’t imported in the current file?”
- Do nothing?
{@link mysterySymbol} is converted into a basic non-interactive mysterySymbol? Con is that to get a working link, you’d have to import symbols that are only used for doc.
- Allow an
import("the-module").mysterySymbol syntax like what was done for types declarations?
- Do a “best guess” and instead of directly going to a
file:line:column, find all references of the given symbol in the project and somehow make the editor open a “peek” widget?
- What if the symbol is located in a dependency, i.e.
node_module?
Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
Reacted by Sebastian Müller, while(true);, Michael Baur, Nicolas Jakob, Matt Bierner, ExE Boss, Orion Kindel, Eshin Griffith, Thomas Cazade, Ryan Parker and 130 more Reacted by Orion Kindel, Braden Napier, Roger Padilla, Fetchinator7, Saulo Vallory and Eduardo Daniel Cuomo Reacted by luketanner-sq, Roger Padilla, Christoph, Saulo Vallory, Federico Sordillo, Jason Kuhrt and Eduardo Daniel Cuomo Reacted by Jeremy W. Sherman and Jayden Seric ActivityyGuy commented on Feb 3, 2020 The JetBrains IDEs have had support for this forever (the see and link syntax is part of the JavaDoc syntax for almost 25 years, now). For me, it's the single most annoying difference in documentation lookup behavior when I switch from WebStorm to VS Code. We even provide a script to our customers so that they can remove all the internal links from the documentation in the d.ts file to make it look less ugly and make it more usable.
WebStorm, too, has the problem of unresolved documentation links when there is no import for the Symbol.
JSDoc actually in a way proposes a solution to this issue with a Syntax to "import" a type from another "module":
/** An event. Its name is module:foo/bar.event:MyEvent.
* @see module:foo/bar.SomeNonImportedSymbol
*/
Adapted from https://jsdoc.app/about-namepaths.html Reacted by Vatroslav Vrbanic, Frank Blendinger, Gabriele Tomberli and Andreas Bergmaier sandersn commented on Feb 4, 2020 More issues to consider in the proposal:
- what kinds of references should be supported? Typescript doesn't support many jsdoc-style namepaths.
- what kinds of urls should be supported? I think parsing urls can get hairy fast.
- Should invalid
@link tags ever have an error?
- how should the parser choose between URL and Symbol references? Should it be a best-guess kind of thing?
Some nice-to-haves that we'll need before any implementation happens:
- Data on frequency of
@link tags and the frequency of URL-vs-symbol as well as various kinds of namepaths.
- Thoughts about effects on incremental parsing. (we're probably OK disabling it here, but we should think about it first.)
- Thoughts about efficiency and complexity of jsdoc parsing:
@link is the only inline tag and the parser currently doesn't have any infrastructure to support that.
Edit: Playing the role of obstinate implementer, I'd say that we could get 80% or more of the benefit of @see and @link just parsing parsing them as special non-tags of the form @see EntityName, which then add a list of references to whatever tag they're on:
/** @param x - a thing; @see foo.bar for details */
Would produce
{
kind: JSDocParameterTag,
name: "x",
comment: "a thing; @see foo.bar for details",
references: ["foo.bar"] // or an actual symbol, after binding is done
}sandersn commented on Feb 4, 2020 mjbvz commented on Feb 4, 2020 Nathan Shively-Sanders (@sandersn) Checkout vscode.d.ts for examples of how VS Code handle documentation links today (For example, see: [CodeActionKinds](#CodeActionKind))
It'd be great if we could move away from our homegrown solution that only works inside vscode.d.ts to a more standard one powered by TS Reacted by Michael Scott-Nelson, Braden Napier and Marko Kaznovac paulmelero commented on Feb 5, 2020 Would it be possible that relative paths were also considered (JSDocs' namepaths)? I was thinking that it could be useful for referencing docs or other assets:
// (might not be the exact syntax)
/**
* Without the `@link`
* @see ../README.md#Troubleshooting
*/
// or
/**
* See {@link ./my_asset.svg}...
*/Reacted by ExE Boss, Christopher Carman, Michael Scott-Nelson, WJH, Braden Napier, Marius Göcke, Slick Kilmister, Miro, Erik Töyrä Silfverswärd, Fetchinator7 and 29 more Reacted by Rohan JasonHK commented on Apr 12, 2020
4. how should the parser choose between URL and Symbol references? Should it be a best-guess kind of thing?
Nathan Shively-Sanders (@sandersn) I think if the string starts with a protocol and not starts with either module:, external: or event:, then it's a URL.
And also, if the string starts with ./ or ../, then it's a relative path. Omitting ./ was not permissible since it will easily be mixed with namepaths.
By the way, should the namepath syntax follow JSDoc, using # for instance members, . for static members and ~ for inner members? Reacted by neumaennl, ExE Boss, Braden Napier, Marius Göcke and Gabriele Tomberli changed the title [-]TSServer – support for @see and {@link} in JSDoc comments[/-] [+]TSServer – support for @see and {@link} in JSDoc comments tags[/+] on Apr 22, 2020changed the title [-]TSServer – support for @see and {@link} in JSDoc comments tags[/-] [+]Editor support for @see and {@link} in JSDoc comments tags[/+] on Apr 22, 2020ackvf commented on Apr 30, 2020 Our code comments sometimes mention symbols in other files. I want to be able to copy such a path LayoutEditor.tsx@acceptsChildren and paste it into goToSymbol field like this:

However, it doesn't work currently and needs to be done in two steps.
taken from microsoft/vscode#96651 Reacted by ExE Boss, Braden Napier, Qwerty (Vítězslav Ackermann Ferko) and Andreas Bergmaier bradennapier commented on May 21, 2020 Ahh interesting, I was actually playing with implementing some of these types of things in a PR but I ended up keeping it simple to make sure there was wide support for it. I also wasn't sure what was possible since I haven't played with the tsServer in the past.
I have to say this is definitely huge IMO. The rich realtime documentation as you code is probably the most underrated and powerful features to come with modern programming / IDE's - and making these hovers/popups more rich and useful will be a huge plus!
My PR aims to be more general purpose by allowing absolute project & workspace linking, but it does reach into the tsServer to grab the definition of the type being documented. I believe in the same light there are other commands here that could grab symbols locations and provide those links... I just wasn't sure how to link to file & line numbers but prob can add it (assuming tsServer provides necessary pieces) if the PR gains support!
Note: The current implementation is broken for relative paths. This is due to the fact they are utilizing the open file to resolve the relative link. This is problematic since we often are imported values from other files. The PR here fixes that issue for the hovers.
At the very least it may provide insight into the vscode implementation requirements!
microsoft/vscode#98238 bradennapier commented on May 21, 2020
A question that subsists is “what to do when {Link (@link)} refers to a symbol that exists in the project but isn’t imported in the current file?”
imo it should not do anything and any links should be required in the file linking them. It simply makes things less magical and makes sense. Auto resolution simply has too many potential caveats and problems that can also be specific to the users environment at some times.
import() is interesting option and should prob be supported as long as the preview text is then transformed to the symbol name automatically which is trivial.
While the jsdoc mentions resolution via something like MyType#my I would say it makes the most sense to just support standard typescript semantics, although the question becomes how to handle the required generics. Foo<any>['baz'] -- perhaps allowing them to be omitted in links and/or just provide the signature Foo<T>['baz'] since this wouldn't affect resolving the location of the definition.
{@link Foo<T>['baz']}
// or just
{@link Foo['baz']}Reacted by ExE Boss, luketanner-sq and Nicolas Jakob sandersn commented on Sep 9, 2020 Thanks to Wenlu Wang (@Kingwl), #39760 is now merged -- it's an 80% solution that supports @see with normal typescript entity name resolution. Next steps will be better VS Code integration and @link support. Reacted by Daniel Shuy, Sebastian Müller, Marcus, Jake Burgy, Ondrej Medek and btoo mjbvz commented on Sep 9, 2020 Here's my proposal on how TypeScript could return the @see and @link tags to editors in a backwards compatible way (shown for a quickinfo response for clarify):
interface QuickInfoResponseBody {
...
tags: JSDocTagInfo[]; // existing
}
interface JSDocTagInfo {
name: string; // existing
text?: string; // existing
// new
links?: ReadonlyArray<JSDocLink>
}
interface JSDocLink {
/**
* Starting index of the link in the jsdoc text (zero based)
*/
textStartOffset: number;
/**
* Ending index of the link in the jsdoc text (zero based, non-inclusive)
*/
textEndOffset: number;
/**
* Where to navigate to when the user clicks the link
*/
link: FileSpanWithContext;
}
-
Older clients could safely ignore the new links field
-
We'd want support for jsdoc links in hovers, suggestion details, and parameter hints to start with.
-
Eventually we could also support JSDocLink in places such as QuickInfoResponseBody.documentation
Unfortunately I couldn't find any similar apis in the LSP to base this on. I think we currently just use markdown links in the LSP KilianKilmister commented on Sep 14, 2020 Nathan Shively-Sanders (@sandersn) Love the little statistic you posted, I'm a big fan of these kind of data-analysis.
What's the thought on using standard markdown links for symbol referencing?
eg.
/** @see [SomeClass](SomeSymbol) */
and
/**
* An Object describing the kind of action that should be performed on the
* lexingState
* - `push`: add the `target` state to the stack
* - `swap`: change to `target` state, replacing the top of the stack
* - `pop`: change to the previous state in the stack. (this option ignores
* any `target` state)
* some inline text (@see [SomeClass]) some more text
*
* [SomeClass]:<SomeSymbol>
*/
Would be neat to have that at some point.
VS code (and i'm assuming the other popular editors aswell) do format and (try) to resolve normal markdown links in comments already, but only works for proper URLs and Paths right now of course.
JSDoc style [link text]{@link namepathOrURL} would work fine too, of course. Just wondering if this is something that's in consideration. It would make it a bit easier for people who write/read a lot of raw markdown but aren't too familiar with JSDoc style Reacted by Sebastian Müller, Eduardo Daniel Cuomo, Cristian, Leon Adler and Gabriele Tomberli yGuy commented on Sep 15, 2020 I'd rather keep the number of different syntaxes for the same purpose as low as possible. The more we are going to support the higher the cost will be for future and alternative IDE vendors to support all the different syntaxes and the lower the chances are that code that you write today will work great with future/alternative IDEs.
I see that one can always can come up with syntax that may look more convenient to write, however I prefer to see a widely accepted and implemented standard that works across editors and tools.
E.g. the JetBrains IDEs have been supporting the "javadoc-like/jsdoc" syntax for years and hence there is quite a big number of libraries that use this documentation format. If we come up with yet "another standard" the worst thing that could happen is that neither of the variants is supported in both big editors and it gets nearly impossible for library authors to write documentation files that work in both IDEs. qJake commented on Sep 16, 2020 I second Sebastian Müller (@yGuy) - if I'm a new developer and I want to write JS/TS documentation, I'm going to search for how to do that and I'm going to get results about (long-standing, widely accepted) JSDoc documentation. So, my opinion would be that we stick as close to the JSDoc spec as possible, for backwards compatibility and continuity reasons. Reacted by Sebastian Müller, Ondrej Medek, Matt Taylor, joemullenix-ks, Feranmi Akinlade and Gabriele Tomberli KilianKilmister commented on Sep 16, 2020 Reacted by Sebastian Müller NoelAbrahams commented on Sep 19, 2020 Duplicate of #5802. Glad to see it's been fixed — it's only been five years. Reacted by Andrei Reacted by Andreas Kohn, Jake Burgy, Thomas Hagström, Arad Alvand, Petar Kovačević, Collin Irwin, Tayler Miller and vibinjoby Reacted by Wenlu Wang, Slick Kilmister, Kamil Kamiński, 4r7d3c0, Rossfuin, Jakub Jirutka, Sam Hall and Andrei Reacted by Wenlu Wang, Ondrej Medek, Andrei and Barry May Reacted by Wenlu Wang and Andrei Reacted by Wenlu Wang and Daniil kajmagnus commented on Sep 26, 2020 Would it be a weird idea to optionally log warnings, and optionally even breaking the build, if a @see link is broken?
E.g. the linked-to thing got renamed / moved / removed, but the linking text wasn't updated.
Nathan Shively-Sanders (@sandersn) wrote:
Should invalid Link (@link) tags ever have an error?
Personally I'd want that yes — optionally breaking the build (a compiler flag?). So annoying if trying to understand old code, and it says "blah blah, see: ..." and then that other related code is ... nowhere. (At the same time, if urgently releasing a security patch, then it'd be stressful to have to spend time cleaning up documentation links? So, optionally?) Reacted by Jason Kuhrt, Jeremy Bensimon, Zeno Jiricek and Gabriele Tomberli qJake commented on Oct 1, 2020 Is there currently an option in TSC that behaves similar to Visual Studio's "Treat warnings as errors" option? If so, we could just log them as warnings and use that pre-existing flag to change them to errors if the project called for it? airtonix commented on Mar 7, 2023
Would it be a weird idea to optionally log warnings, and optionally even breaking the build, if a @see link is broken?
E.g. the linked-to thing got renamed / moved / removed, but the linking text wasn't updated.
Nathan Shively-Sanders (@sandersn) wrote:
Should invalid Link (@link) tags ever have an error?
Personally I'd want that yes — optionally breaking the build (a compiler flag?). So annoying if trying to understand old code, and it says "blah blah, see: ..." and then that other related code is ... nowhere. (At the same time, if urgently releasing a security patch, then it'd be stressful to have to spend time cleaning up documentation links? So, optionally?)
This should be an eslint rule (or a whatever-your-lint-tool-is-rule).
I'm not about to install vscode in a github workflow just to lint comments 🤣 ssalka commented on Apr 18, 2023 Wanted to chime in on this because I thought it already worked this way, but turns out it doesn't:
If I want to do a @see {@link ...} referencing a variable in another file, I shouldn't have to add a literal import statement of the variable to be able to do this with JSDoc. Rather, I'd expect to be able to use TypeScript's existing import() type syntax, which essentially abstracts the literal import away into a comment, which I can feel comfortable knowing it definitely won't have any runtime effect. I could use a literal import type statement, but if I'm only trying to do a @see @link, it feels better to accomplish the import also through JSDoc (keeping the import close to where it is used rather than with actual imports that are needed for runtime behavior).
The import("the-module").mysterySymbol suggestion in the original section on Non-imported symbols seems like the most TypeScript-y way to accomplish this, and follows the heuristic line of thinking "if I can write const x: Type = ..., I should be able to write /** @see {@link Type} */ for any valid Type, including such mysterySymbol import types" Reacted by btoo, Andrzej Wódkiewicz, Nicolas Jakob, Lukas, Thibault, Andre Rabold, Feranmi Akinlade, Gabriele Tomberli, Jaakko Sirén and blakewats 500-internal-server-error commented on Oct 14, 2024 Could support for differentiating MyClass.staticMethod and MyClass#instanceMethod be added? It seems like a minor yet useful change. Currently I need to do {@link MyClass.instanceMethod | MyClass#instanceMethod} to do this, and even then it's only a visual thing, not enforced to be static/instance. Reacted by Ondrej Medek, btoo and Sebastian Müller
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|