tsdoc
tsdoc copied to clipboard
No types in comments?
I tried the playground, but when I try something like
* @param {number} x - The first input number
it gives
(7,4): The @param block should be followed by a parameter name
(7,11): Expecting a TSDoc tag starting with "{@"
(7,18): The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag
@octogonz @iclanton Hello guys, does tsdoc support type annotations? f.e. @param {HERE} x - The first input number?
In TypeScript, types are specified using in the language itself. It doesn't make sense to declare them in the comment. When people are writing new TypeScript code using TSDoc, it's a mistake to put types in a comment. The initial implementation of the TSDoc parser is "strict" and reports an error.
But this practice is valid with JSDoc, since it was designed for JavaScript. Because of that, it's somewhat common to find that notation in legacy TypeScript code. To accommodate this, the plan is to implement a "lax" mode that allows the TSDoc parser to accept these notations. We'd recommend to use "strict" mode for new projects, and "lax" mode for existing projects.
That's the plan, but the first priority is to finish the strict TSDoc specification. It's close to being done, but there's a few major changes that need to get incorporated before the "1.0" release:
- Integrate the revamped declaration reference syntax, which was finalized a couple months ago
- Implement some missing Markdown constructs such as lists, boldface, etc.
- Expand TSDoc to include full HTML parsing, whereas currently HTML tags are treated as a flat list of tokens rather than a tree
- Make the escaping rules more rigorous, e.g. adding support for HTML entities
We're making steady progress on these things, but it takes time.
In TypeScript, types are specified using in the language itself. It doesn't make sense to declare them in the comment.
This is normally true.
making steady progress on these things, but it takes time
Nice! Always great to hear progress being made. :)
The reason I want source-code-agnostic JS/TSDoc is to be very specific about my docs and how they are presented. I'd like comments to be absolute source of truth for my docs, regardless source code (though a case-by-case opt-in feature could be nice).
Unfortunately all JSDoc tools I've tried fumble on TS code because they rely on the source (and an associated AST).
What I want to do is the following sort of documentation. Under the assumption that all classes in the project I'm documenting are mixable classes, then most files will look something like this:
AwesomeFeature.ts
// AwesomeFeature.ts
import { Mixin, MixinResult, Constructor } from 'lowclass'
// these two "mixable classes" are defined the same way as AwesomeFeature is below
import CoolFeature from './CoolFeature'
import OtherFeature from './OtherFeature'
/**
* @class AwesomeFeature - Provides some awesome feature
*/
function AwesomeFeatureMixin<C extends Constructor>(Base: C) {
class AwesomeFeature extends CoolFeature.mixin(OtherFeature.mixin(Constructor(Base))) {
/**
* @property {boolean} performingAwesome - Whether awesomeness is currently happening or not.
*/
performingAwesome = false
/**
* @method doAwesome - Do awesome with this.
* @param {number} howMuch - How much awesome to do.
* @returns {Promise<undefined>} - Whether awesomeness succeeded or not.
*/
async doAwesome(howMuch: number): Promise<void> {
this.performingAwesome = true
// ...
this.performingAwesome = false
}
}
return AwesomeFeature as MixinResult<typeof AwesomeFeature, C>
}
// export a class that can also be used as a mixin
export const AwesomeFeature = Mixin(AwesomeFeatureMixin)
export type AwesomeFeature = InstanceType<typeof AwesomeFeature>
The user of AwesomeFeature can extend it as a class, or use it as a mixin:
class Foo extends AwesomeFeature {/* ... */}
// or
class Foo extends AwesomeFeature.mixin(SomeOtherClass) {/* ... */}
CoolFeature and OtherFeature work the same way, as classes or mixins.
See what I'm trying to do? The mixability of my classes is inherent throughout the project, and I want to document them very simply.
Tools like TypeDoc try to document (infer) too much, and output too much noise. I don't want machine-generated "docs" for everything that can possibly be found in my source code. I want to make clean simple semantic human-readable docs, and don't mind the extra manual labor that will be needed to achieve it.
Someone interested in every single type in the code base can just open the source in VS Code.
I'm thinking of a possible approach: make or use a code-agnostic comment extractor, then pass that to Doctrine, and go from there with the Doctrine's JSON output for writing simple custom humanized docs.
I see what you mean. I'll start by saying that mixins are overcomplicated, difficult to debug, and difficult for users to understand. Nobody should be excited about mixins. I really mean that!
That said, now let's talk about how mixins worked awesome for my own project API Extractor. 😅 Please check out https://github.com/microsoft/tsdoc/issues/137#issuecomment-446446564 for the full details and proposal.
The TL;DR:
- You need to include an interface and/or namespace that tells the type system (and documentation engine) about the members of your class
- We're proposing a TSDoc tag
@partOfthat would tell the documentation engine to treat these declarations as a single entity - We're proposing a tag
@documentAsthat tells the documentation engine to display it as being a "class" or "mixin"
I didn't pursue this feature because API Extractor is literally the only project where I can justify using mixins. But if you like this idea, we could do a quick PR to add the @partOf and @documentAs tags to TSDoc. (And if you use API Extractor, we could try to prioritize this feature; I suspect it's relatively easy to implement.)
include an interface and/or namespace that tells the type system (and documentation engine) about the members of your class
The one in Leafdoc is great; it supports multiple inheritance (whether that's class mixins, concatenation of objects, or whatever) that can be documented across multiple files, and is source agnostic. An @class comment can have any number of @inherits comments associated with it. However the syntax isn't exactly JSDoc, though similar.
What would a simple example of @partOf and @documentAs look like?
See the other issue I linked above
Ah, thanks. It seems like a little bit more complicated than I'd like.
I think of TypeScript as an implementation detail for the mixins. I'd like to document them without regards to the specific language, avoiding to document all the TypeScript-specific mechanisms that make up a mixin in TypeScript.
I really like how it works in Leafdoc:
/**
* @class Foo
*/
blah blah, this syntax { is ) not ) any & valid ] code
/**
* This method return a number and has a string param
* @method fooMethod: number
* @param name: string
*/
blah blah, this syntax { is ) not ) any & valid ] code
/**
* @class Bar
*/
blah blah, this syntax { is ) not ) any & valid ] code
/**
* @method barMethod: void
* @param shouldDoSomething: boolean
*/
blah blah, this syntax { is ) not ) any & valid ] code
/**
* This class extends from both Foo and Bar
* @class Baz
* @inherits Foo
* @inherits Bar
*/
blah blah, this syntax { is ) not ) any & valid ] code
/**
* @method bazMethod: void
*/
blah blah, this syntax { is ) not ) any & valid ] code
Here's the example output of the above example (my output template is WIP, it'll look better later!):
With this particular template, the inherited methods are visible in <details> drop downs:
This simple system allows documenting compositional patterns, without being tied to the source (@namespace can be used in place of @class to document non-class compositional patterns).
I really like the simplicity of Leafdoc, but it would be nice to be able to achieve the same with a standard syntax like JS/TSDoc, because then text editors (f.e. VS Code) have official support for them.
That makes sense. However your examples only use primitive types like string.
What will you do with the parameter whose type is Map<string, Widget[]>? How will you document generic parameter constraints? Etc
your examples only use primitive types like string.
the comment parser is source agnostic so it doesn't matter much: I could put anything in place of string, for example @method fooMethod(name: module>foo/bar/baz.ts#FooClass), and it will give me that string in the output for the type:
It is flexible, allowing my docs to have the meaning that I want them to have. I can determine how to link to that class FooClass inside of foo/bar/baz.ts my own way by building on top of the output.
But anywho, I decided to just make my own JSDoc parser using RegExps, it will do similar to Leafdoc by simply returning the content of the @tags as strings. Then a higher-level tool could decide what to do with the parts.
Later it would be nice to upgrade it to a lexer that works over a stream of incoming text, for speed.
A higher-level tool could choose to be source-aware and to parse the types, parse the description with specific syntax like reStructuredText, etc. F.e. jsdoctypeparser is a tool that will be usable on top of it.
For my case though, I'll take the strings and make something minimal and source agnostic, with markdown handling for the descriptions.
TypeScript supports types in the JSDoc comments. I wonder what it's using for that. Maybe it's all just built into TypeScript, but it'd be nice if it could be used standalone...
I think a generic foundation may be good for tools to build upon (f.e. a type-aware source-aware tool).
Plus, it'd be nice to also document anything in a project, like CSS, HTML, Less, shell scripts, PHP, Ruby, or other sorts of files, using the same doc tool.
It sounds like you are after JSDoc with the commentsOnly plugin. https://github.com/jsdoc/jsdoc/blob/master/plugins/commentsOnly.js
Looking forward to trying the "lax" mode once that's out. :)
@Gerrit0 Oh interesting, I hadn't seen that plugin before. I'll check it out...
EDIT: Ironically, the JSDoc site doesn't document the API (and plugin hooks), or at least there's no immediately obvious link to it. I do see JSDoc comments in the source though.
Everything I try has some critical issue. Writing
/**
* @class Foo
* This is a cool class.
*/
causes JSDoc to break, and output nothing after it reaches that comment.
😫
You'd think, that it could at least not fail just because This is a cool class. comes after the @class line.
It'd be great to have a tool that reads comments, and always returns the content of every comment in some understandable form without tripping up on insignificant details like above.
EDIT: more rant about inconsistent JSDoc syntax:
I don't like the inconsistencies in the syntax across tags. From their docs:
/**
* @function {foo} - This has the name of the function, "foo", inside the curlies. ????
* @param {string} bar - But this one has the type inside the curlies and the name outside!!!
*/
function foo(bar) {}
With my above proposed regex solution I linked, every tag will have the same syntax and structure, and always output something. Easy!