tsdoc
tsdoc copied to clipboard
How to enforce docs on Typescript interface and its properties using EsLint?
I am looking to enforce documentation on the interfaces and all of its properties using eslint. I have installed eslint-plugin-tsdoc
package in my project. Is there a rule to enforce it?
Thanks
Not yet, but we've been wanting to make one! Want to propose a design?
@micthiesen brought up the same question in #228. The first step is to agree on a design:
How would the rule work? (Does it check every class/member/function? Only exported ones? Only ones marked as @public
? What if the property is really simple?)
What options would it support? (Is there a minimum number of words required in the documentation? Is there a way to "opt-out" for a given item?)
Maybe we could base the design on an existing ruleset like eslint-plugin-jsdoc. But if we do that, which subset of features should we start with?
@octogonz If basing off of eslint-plugin-jsdoc rules, it looks like require-description and require-jsdoc would be two generic rules to start with that would satisfy #228 and would lead to further rules for solving #209.
Starting with Is there a minimum number of words required?
, for some of jsdoc rules they have a base rule where the minimum requirement is just that a non-empty value is present. In addition, they have `require-[context]-complete-sentence> rules. Would starting out with a basic non-empty content requirement be sufficient?
Would starting out with a basic non-empty content requirement be sufficient?
Sure, although I think the more interesting design question is around which things need comments.
Fantasizing for a moment, in our own projects, I think I'd like a policy such as:
- "Documented" things must have at least 5 words of TSDoc summary text, but no further requirements beyond that (e.g.
@param
and@remarks
are NOT required) -
{@inheritDoc}
counts as documentation - Docs are required for every top-level declaration (
class
,interface
,function
,type
,namespace
), but only if it is exported by the file - Class members require docs only if they are functions (not properties or fields), and only if they are
public
- But class constructors do NOT require docs (in fact API Extractor autogenerates the
constructs a new instance of the ___ class
for you) - Interface members require docs only if they are functions (not properties or fields)
- Namespace members require docs only if they are exported (i.e. externally visible)
This may seem lax, but it's based on a philosophy that it's bad to write documentation that doesn't convey any new information. For example if the lint rule makes people write something like this...
/** Stores a width and height. */
interface ISize {
/** The width component of the size. */
width: number;
/** The height component of the size. */
height: number;
}
...it doesn't just waste screen space, it normalizes an attitude that documentation is an empty formalism, jumping-through-the-hoops to appear like we have have documentation, rather than being about trying to communicate non-obvious information that helps developers understand and use your APIs.
Does that seem reasonable? If so we could take something like this as the goal, and maybe we can then start by implementing a meaningful subset of it.
@arenglish are you interested to contribute a PR?
@octogonz
This may seem lax, but it's based on a philosophy that it's bad to write documentation that doesn't convey any new information
I completely agree with that and know that many values like variables and class members can usually be reasonably documented just with just an appropriate name.
I'm very new to tsdoc, I just came across it while searching for a good in-code documenting system for our angular monorepo, and found Compodoc and Typedoc, both of which seem to be implementing something similar to tsdoc except that it's based on jsdoc.
I would definitely be interested in contributing a PR for this, but I'm going to pull down the code base and get familiar with the API Extractor so I can have more context before starting.
I think all the policy points you listed are a solid starting point. In our case, class constructors can sometimes get complex making docs on constructors that require arguments a potential need, but I'll think through the different use cases we have over the next few days to compare with the ones you've come up with.
In our case, class constructors can sometimes get complex making docs on constructors that require arguments a potential need
Seems reasonable. By the way, we generally solve this by avoiding anonymous types. Instead of this:
class Vector {
// anonymous type literal
constructor(options: { width: number; height: number; }) { }
}
...we would always write it like this:
interface IVectorOptions {
width: number;
height: number;
}
class Vector {
// named API
constructor(options: IVectorOptions) { }
}
Thus the documentation requirements for IVectorOptions
should avoid the need for documenting Vector
's class constructor. It also makes it easier to format the documentation for the IVectorOptions
structure.
Such a rule would be highly desirable.
tsdoc looks very promising but not having 'require' rules is a show stopper for me It means developers can go about writing logic which is undocumented and eslint will not complain about it
https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-jsdoc
I also want to enforce TSDocs. I more or less agree with @octogonz’ comment, but I think the users need to have a way to disable individual top-level declaration types (class
, function
/method
, …), as well as define the ESlint level (off
, warning
, error
) for entire rule, as well as for the individual top-level declaration types.
I wish this would be implemented ASAP. Unfortunately, I am not that good coder, so I can’t help you implementing it.
I also want to enforce TSDocs. I more or less agree with @octogonz’ comment, but I think the users need to have a way to disable individual top-level declaration types (
class
,function
/method
, …), as well as define the ESlint level (off
,warning
,error
) for entire rule, as well as for the individual top-level declaration types.I wish this would be implemented ASAP. Unfortunately, I am not that good coder, so I can’t help you implementing it.
breaking lint plugins to individual rules probably provides that ability. doesn't it?
Any updates on this? Really wanting to use tsdoc but as @bigman73 mentioned this is also a show stopper for me.
Let me push this. We really need this feature in our dev team. Any updates? Or does anyone know an alternative eslint docs plugin that works with typescript and has this feature?
I ended up looking at tsdoc as I observed that our codebase lacked documentation and I was hoping that this will at least allow us to force people to write some documentation but now I see that this plugin can check the format of the docs but not the absence of the docstrings... bit confused as that would have being the first feature I would have implemented.
Opened since 2020. Any news on that? Or is the plugin dead?
So, for those who are still waiting for MS to move, I started implementing a new eslint plugin to enforce the usage of TSDoc comments on exported types. There is a preview version that checks the high level types (not the public members of classes and interfaces yet). It is not published on npm, but you can install it directly from github:
npm install -D https://github.com/bmarotta-ease/eslint-plugin-require-tsdoc.git
Comments, suggestions and contributions are welcome.
Although this rule is deprecated, it works in our codebase to force tsdoc:
https://eslint.org/docs/latest/rules/require-jsdoc
Solved it by using eslint-plugin-jsdoc
, adding the jsdoc/require-jsdoc
rule and configuring the AST types on the contexts option. Reference: https://github.com/gajus/eslint-plugin-jsdoc/issues/496#issuecomment-591204300
// .eslintrc.js
// ...
"jsdoc/require-jsdoc": [
"error",
{
publicOnly: {
cjs: true,
esm: true,
window: true,
},
require: {
ArrowFunctionExpression: true,
ClassDeclaration: true,
ClassExpression: true,
FunctionDeclaration: true,
FunctionExpression: true,
MethodDefinition: true,
},
contexts: [
"TSInterfaceDeclaration",
"TSTypeAliasDeclaration",
"TSEnumDeclaration",
"TSPropertySignature",
],
},
],
// ...