Grouping Functions In JSDoc Generated Documentation - javascript

I'm using documentationjs (which uses jsdoc under the hood) to handle the generation of docs for a lib I'm working on. My lib is written is ES6 and is fully functional, and at present the documentation generated is an alphabetical list of all the functions from all the modules in the lib. This makes it very hard to find what you are looking for. How should I use jsdoc comments so that functions from one file are grouped together in the documentation?
For example, given the following file …
/**
* Docs for alpha
*/
export const alpha = () {};
/**
* Docs for beta
*/
export const beta = () {};
/**
* Docs for charlie
*/
export const charlie = () {};
… how should I use jsdoc comments to ensure the three functions are grouped together under 'Example' in the documentation?
I have tried defining a module at the top of the class: /** #module Example */ but although this generates an item called 'Example' in the docs, the functions are not grouped underneath it.
I have tried adding #memberof Example to the documentation of the individual functions, but this has no effect.
I am aware of this question, but it doesn't work for me, possibly because of the ES6 imports. There is no mention of its use with #module in the docs.

It appears that documentationjs doesn't support JSDoc style grouping in its generated docs, however, it is possible to group functions using a slightly different syntax. I discovered this through trial and error due to documentationjs's (ironically) poor documentation:
/** #module Example **/
/**
* #memberof Example
*/
const alpha = () => {};
Note: there is no module: prefix for the #member argument.

Perhaps you can try this workaround for now, until jsdoc implements grouping.
How to display Javascript methods in a 'group' in JSDOC?

I think you need to use #module in this way:
/** #module myModule */
/** will be module:myModule~foo */
var foo = 1;
/** will be module:myModule.bar */
var bar = function() {};
As described here.

Related

JSdoc for js closures

Using jsdoc version 3.6.2
I have a project with tons of jsdoc documentation written, but unfortunately jsdoc won't parse it into the format I'm expecting.
We have numerous js files that create objects and then use function closures to define methods on those objects. I would like jsdoc to pick up those methods and associate them with the given module.
/** #module #mymodule*/
var mymodule = {};
/** This module is my very special module */
(function() {
var started = false;
/**
* #memberof module:mymodule // I have tried this, #name, #lends, etc...
* Start the module
*/
mymodule.start = function() {
started = true;
};
})();
It seems no matter what I do, I can't get the start method to actually show up as a documented method of the mymodule module. If I use #alias on the method, then it shows up as a global on the jsdoc index page, but that doesn't make for a very readable index page if it just dumps 10k links.
Anyone know how I can get this method to show up on the mymodule.html page?

JSDoc3 does not generate hyperlinks to namespaces in NodeJS

I bet this is a stupid question but I somehow can't find the reason for this in any document I have found since this morning.
I am experienced in using JavaDoc but somehow even though the syntax of #link is the same, JSDoc3 simply does not generate hrefs to the related elements. I have tried out every possible way for the namespaces to link (also obviously wrong ones), but non of them changes the result a bit. I expected to receive a link by writing {#link #myFunction} or at least {#link MyClass#myFunction}, but neither of this created a hyperlink. Here is the code I have tested this with:
/**
* See {#link myOtherFunction} and [MyClass's foo property]{#link MyClass#foo}.
* Or look at {#link https://github.com GitHub}
*/
function myFunction(){};
/**
* See {#link #myFunction} or maybe {#link #myFunction()}
*/
function myOtherFunction() {};
I am generating it with ./node_modules/.bin/jsdoc ./* --configure ./conf.json and my default config file is:
{
"tags": {
"allowUnknownTags": true
},
"source": {
"includePattern": ".+\\.js(doc|x)?$",
"excludePattern": "(^|\\/|\\\\)_"
},
"plugins": [],
"templates": {
"cleverLinks": true,
"monospaceLinks": false,
"default": {
"outputSourceFiles": true
}
}
}
(it makes no difference if I write "cleverLinks": false,)
This is how my output looks like:
So as one can see the URL is generated properly but the namespaces are not.
I am just badly confused since I can nowhere find a description that something must be done in order to generate hrefs to my namespaces. Additionally jsdoc says:
The {#link} inline tag creates a link to the namepath or URL that you specify. When you use the {#link} tag, you can also provide link text, using one of several different formats. If you don't provide any link text, JSDoc uses the namepath or URL as the link text.
which does not sound like there needs to be done anything in order to generate links to the namepaths.
And it also defines the syntax to be:
{#link namepathOrURL}
[link text]{#link namepathOrURL}
{#link namepathOrURL|link text}
{#link namepathOrURL link text (after the first space)}
My namepaths are okay as well since webstorm is able to resolve them directly.
What am I missing so badly?
Best regards,
Vegaaaa
I have found out my issue was related to the usage of JSDoc with CommonJS (NodeJS). After several hours of googling and trial and error I have managed to end up with how it working differently in NodeJS. I might play around with #inner and #instance but this resolves the question why JSDoc did not want to generate links for my NodeJS Code.
It is due to the fact that CommonJS's scope works differently to client side JS, which has one reason in the definition of NodeJS modules. Thus one need to tell JSDoc how to resolve a variable by adding the #module tag for a module and referencing to members of a module by resolving its relationship like {#link module:MODULE_NAME~instanceName}.
Here is an example with the corresponding generated html. Hope this helps someone running in the same issues like me.
Best regards,
Vegaaaa
/**
* #module lib
*/
/**
* #constructor
*/
var SomeClass = function () {
};
/**
* Some doc...
*/
var moduleFunction = function () {
/**
* #type {number}
*/
var innerVar = 0;
/**
* #type {number}
*/
this.instanceVar = 0;
/**
* #memberOf module:lib~moduleFunction
*/
function staticVar() {
console.log(0)
}
}
/**
* Link to this module (identified by #module lib in the beginning): {#link module:lib} <br/>
* Link to my constructor: {#link module:lib~SomeClass} <br/>
* Link to a module function: {#link module:lib~moduleFunction} <br/>
* Link to an instance variable of a module function: {#link module:lib~moduleFunction#instanceVar} <br/>
* Link to a inner variable within a module function: {#link module:lib~moduleFunction~innerVar} <br/>
* Link to a static variable within a module function: {#link module:lib~moduleFunction.staticVar} <br/>
*/
function documentedFunction(){}

JSDoc in VS code for documenting function with module's type

I want to document a function written in another module, which uses http.ClientRequest typed parameter. I want something like this, but it does not work:
/**
* #param {ClientRequest} req
*/
function setToken(req) {
}
I have tried also #param {http.ClientRequest}, but it did not work.
Update:
Basically I solved that problem by importing the required module by import http from "http";. However, I don't want to import it because this module does not use http module but provides helper functions.
After improve answer from IGx89 I got a shorter variant without typedef. I prefer this variant when I reference to another module one time:
/**
* #param {import('http').ClientRequest} req
*/
function setToken(req) {
}
But if you need reference to some type from another module with long path variant with typedef looks shorter.
Add the following to the top of your file:
/** #typedef {import('http').ClientRequest} ClientRequest */
I had this same problem myself (though regarding a module in my own app) and also had a very hard time finding the solution. I eventually figured out the above syntax by reading through this issue in the TypeScript GitHub repo: https://github.com/Microsoft/TypeScript/issues/14377
It does not work because it is a custom type JSDoc don't know. You have to setup your own definition with a #typedef.
/**
* A number, or a string containing a number.
* #typedef {(number|string)} NumberLike
*/
/**
* Set the magic number.
* #param {NumberLike} x - The magic number.
*/
function setMagicNumber(x) {
}
See the full examples on JSDoc typedef tag definition examples
I made an example which worked for me with JSDoc 3.5.3
/** #typedef {ClientRequest} TestReq */
/**
* #param {TestReq} req
*/
function setToken(req) {
}
JSDoc output image

How to write concise JSDoc using AMD modules and factory-style constructors?

I'm trying to add JSDoc in to a project where the majority of sources follow the following guidelines:
Scripts are AMD modules which define classes (they export a constructor function )
Constructors are really factories; they return anonymous objects (instead of populating this) to avoid undesired behavior if new is omitted.
I would like to document this using JSDoc, but "getting it right" currently involves what seems to be a lot of redundancy:
/**
* These are my docs for SomeClass.
* #module path/to/some-module
*/
define(
/** #lends module:path/to/some-module */
function () {
/**
* Construct some object.
* #constructor
*/
function SomeClass(a, b, c) {
var somePrivateVariable;
function somePrivateFunction() {}
return {
/** #memberof module:path/to/some-module~SomeClass# */
someMethod: function () {},
/** #memberof module:path/to/some-module~SomeClass# */
someOtherMethod: function () {}
};
}
return SomeClass;
}
);
I'd like to shorten this. In particular, the long "path" after all those #memberof tags is tedious and noisy, especially when there are a lot of methods. The #lends is also annoying, since from a human-reader perspective it's totally redundant.
Is there a better way to do this without rewriting or refactoring the code itself?

Bad type annotation. Unknown type

I keep getting the warning mentioned above but can't figure out why. I've added deps.js and deps.js contains a reference to the type.
Here is the offending code:
goog.provide("MyCompany.MyApp.dom");
MyCompany.MyApp.dom.getArticleAmountInput_=function(){
return document.getElementById("articleAmount");
};
/**
* Gets the article amount input value
* #type {function(this:MyCompany.MyApp.dom):number} */
MyCompany.MyApp.dom.getArticleAmount=function(){
var tmp=this.getArticleAmountInput_();
return (tmp)?tmp.value():undefined;
};
In deps.js:
goog.addDependency('../../MyCompany/MyApp/dom.js', [ 'MyCompany.MyApp.dom'], []);
Code loads in html so it does find the class at runtime. Here is how I compile the code:
java -jar ../../compiler.jar \
--compilation_level=ADVANCED_OPTIMIZATIONS \
--formatting=PRETTY_PRINT \
--warning_level=VERBOSE \
--summary_detail_level=3 \
--js=MyCompany/MyApp/dom.js \
--js=closure/goog/deps.js \
--js_output_file=out.js
And it keeps giving me the warning:
WARNING - Bad type annotation. Unknown type MyCompany.MyApp.dom
[update]
Tried to leave out the goog.provide completely and leave out the js=closure/goog/deps.js when compiling and changed everything to lower case but keep getting the same warning on this code:
//goog.provide("mycompany.myapp.dom");
var mycompany={};
mycompany.myapp={};
mycompany.myapp.dom={};
mycompany.myapp.dom.getArticleAmountInput_=function(){
return document.getElementById("articleAmount");
};
/**
* Gets the article amount input value
* #type {function(this:mycompany.myapp.dom):number} */
mycompany.myapp.dom.getArticleAmount=function(){
var tmp=this.getArticleAmountInput_();
return (tmp)?tmp.value():undefined;
};
[update]
The thing is that when I add a typedef I get warnings that myapp.dom is never defined but when I let the code determine what the type is I get Bad type annotation.
Tried to add a typedef like so:
/**
* #typedef {{getArticleAmount:function(this:myapp.dom):?number}}
*/
myapp.dom;
But don't realy see why as goog.provide should create the myapp.dom and the compiler should know that.
[update]
I have created the following myapp.workflow from constructors. Now the compiler should recognize the type and Eclipse can code assist. Not sure if this is the way to do it but I'll try to re factor a small project.
Setting up the main types in types.js
// source: js/mmyapp/types.js
goog.provide("myapp.types");
/** #constructor */
var gooblediegoog=function(){};
/** #constructor */
gooblediegoog.prototype.WorkFlow=function(){};
/** #constructor */
gooblediegoog.prototype.Dom=function(){};
myapp.types=new gooblediegoog();
A file that isn't used at all in my code but tells Eclipse how to auto complete:
// source: js/myapp/forCodeAssist.js
/** #const {boolean} */
var ALLWAYSFALSE=false;
if(ALLWAYSFALSE){
/**needed for Eclipse autocomplete
* #constructor
*/
var MyApp=function(){};
MyApp.prototype.types=new gooblediegoog();
Window.prototype.myapp=new MyApp();
MyApp.prototype.workflow=new myapp.types.WorkFlow();
MyApp.prototype.dom=new myapp.types.Dom();
}
An implementation of workflow:
// source: js/myapp/workflow.js
goog.provide("myapp.workflow");
goog.require("myapp.types");
goog.require("myapp.dom");
/** #returns number|undefined */
myapp.types.WorkFlow.prototype.createOrder=function(){
return myapp.dom.getArticleAmout();
};
myapp.workflow=new myapp.types.WorkFlow();
window['console'].log(myapp.workflow.createOrder());
This can be converted to a myapp.workflow.createOrder=... syntax by replacing myapp.types.WorkFlow.prototype with myapp.workflow, removing myapp.workflow=new myapp.types.WorkFlow() and removing the goog.require("myapp.types"). Maybe this can be automated in the build/compile process if needed.
I am not sure if creating a single object with the help from a constructor function is much more expensive than just having goog.require create myapp.workflow and adding properties to it as I used to do (and as it's done in closure library).
Anonymous types (namespaces or singletons) don't have specific types in Closure-compiler and cannot be used as a type name in an annotation. Only constructors and interfaces can be used as new type names. (typedefs can be used but are really just shorthand annotations)
In many cases the compiler will correctly infer the types and you will not need to annotate it. In your specific case, it looks like the problem is your use of the this keyword. Using the this keyword in a static object / namespace is dangerous and not supported. The compiler will raise a warning. While you can suppress the warning with a #this annotation, that is not the correct action here as you are not specifically specifying the this reference by using .call or .apply.
The solution is to use the full object name:
/**
* Gets the article amount input value
*/
mycompany.myapp.dom.getArticleAmount=function(){
var tmp=mycompany.myapp.dom.getArticleAmountInput_();
return (tmp)?tmp.value():undefined;
};
For the full technical details, reference the This this is your this post.

Categories

Resources