JSDoc3 does not generate hyperlinks to namespaces in NodeJS - javascript

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(){}

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?

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 use jsdoc for a meteor application

What is the correct way to use JSDoc within a meteor application?
Below there is my way to document the code, but there is no 'connection' between all parts.
Everything belongs to the example template, so the output of jsdoc should be structured correctly.
How can I improve this documentation?
Template.example.helpers({
/**
* Get all categories
* #name categories
* #return {Cursor}
* #summary Cursor categories
*/
categories() {
return Categories.find({});
},
});
Template.example.onCreated(
/**
* If template is created (still not rendered), ReactiveDict variable is initialized
* #function
* #name onCreated
* #summary Set ReactiveDict
*/
function() {
this.something = new ReactiveDict();
}
);
Template.example.events({
/**
* Clicking on category will show a console message
* #event
* #summary Console message
*/
'click #category': (event, template) => {
console.log('nice')
}
});
Where I work, we encountered the same situation a few months ago, what we concluded was that jsdoc was just not adapted to auto-doc with Meteor's implementation. We ended up using https://github.com/fabienb4/meteor-jsdoc which gives us full satisfaction.
It basically extends jsdoc syntax with meteor specific keywords so you can specify what is a Meteor.call, what is a collection helper and so on. Once configured and running, the output is basically what Meteor's documentation used to look like before 1.3 (as the author says, it's "Based on the templates from Meteor own docs.").
Edit: As we don't use Meteor's templating system, I don't have an existing example but I adapted a collection helper to your case, tell me if there is anything unclear. The trick is to play with #memberOf, #isMethod, etc depending on how you want your doc to be displayed.
/**
* #memberOf Foo Template
* #summary Returns Bar conversation attached to stuff
* #param {String} fooId
* #param {Boolean} forced # Use to create foo when it's not found
* #returns {Object} Bar
*/
getStuff: function(fooId, forced=false) {
'use strict';
/** your code **/
}

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.

Annotating a class received from JSON server call

I am trying to properly annotate all my Javascript code and am still a beginner in this field.
I get objects from a server call that are directly in json. Those objects are passed to functions and I call members directly. It obviously is very error prone while obfuscating so I am trying to annotate everything properly.
My understanding is that (i) I should create a class for this object even though it is never created directly with new and (ii) I should be careful with member names since they are fixed by the server response and should not be changed (or should be aliased beforehand).
I have two questions: are my asumptions correct ? how to do the annotation based on that.
Here is a sample code to illustrate
$.get("url.php", function(data) {
process(data);}, "json"); // <= returns {"a":"abc","b":1}
function process(data) {
$("#someElement").html(data.a + data.b);
}
Here is the class I was planning on creating for closure compilation purposes
/**
* The object that is sent back from the server
* #constructor
*/
function ServerResponse() {
/** #type {string} a */
this["a"] = "";
/** #type {number} b */
this["b"] = 0;
}
Here is the annotation for my process function
/**
* Process data from the server
* #param {ServerResponse} data: the Object sent back from the server
*/
Is my annotation correct? Is it robust to obfuscation?
Thanks a lot for your help
If you quote property names, you need to quote them consistently at every usage. If you haven't see this, you should read:
https://developers.google.com/closure/compiler/docs/api-tutorial3
So that your first snippet would be:
function process(data) {
$("#someElement").html(data['a'] + data['b']);
}
If you are trying to avoid quoting or if you would like the compiler to type check the usage of the properties (quoted properties references are not checked), you should define an extern file to include with the compilation of your source:
/**
* #fileoverview
* #externs
*/
/** #interface */
function ServerResponse() {}
/** #type {string} */
ServerResponse.prototype.a;
/** #type {number} */
ServerResponse.prototype.b;

Categories

Resources