JSDoc, documenting functions stored inside an object - javascript

I'm having trouble getting functions to show in JSDoc when they are stored inside an object. So I have something like:
/**
*/
var methods = {};
/**
Get all resources
*/
methods.getResources = function(){
return name;
}
How would I have the getResources function show up in JSDoc? I've tried adding #class to methods with no luck.

#namespace and #memberOf should be what you're looking for.
/**
* #namespace methods
*/
var methods = {};
/**
* Get all resources
* #memberOf methods
*/
methods.getResources = function(){
return name;
}

Related

ES6 Symbol properties not detected by Visual Studio Code Intellisense

I have the following two objects in Visual Studio Code, each with one public and one private (via symbol) method:
const symKey = Symbol();
/** #namespace */
var objLiteral = {
literalPublicFn1() {},
/**
* You found the secret fn!
*/
[symKey]() {},
};
/** #namespace */
var objAssigned = {};
/** #memberof objAssigned */
objAssigned.laterPublicFn1 = function() {};
/**
* You found the secret fn!
* #memberof objAssigned
* */
objAssigned[symKey] = function () {}
For both objects, the public methods are autocompleted accurately. However, when I try to access their private methods, autocompletion only works for the object literal:
Whereas for the later-assigned object, no autocompletion appears whatsoever.
Any solutions to this, or is this just a limitation of VSC's intellisense?

How to document a factory that returns a class in angular with ngdoc?

Given an angular app with a factory that returns a class, as such:
angular.module('fooApp').factory('User', function(){
function User(name){
this.name = name;
}
User.prototype.greet = function(){
return "Howdy, " + this.name;
}
return User;
});
Using ngdoc (the special flavor of jsdoc angular uses), how do I document the initializer without defining it as a method?
Right now, this is what I've tried:
/**
* #ngdoc service
* #name fooApp.User
* #description User factory.
*/
angular.module('fooApp').factory('User', function(){
/**
* #ngdoc method
* #methodOf fooApp.User
* #name Initializer
* #description Initializes a new User object with a name
*/
function User(name){
this.name = name;
}
User.prototype.greet = function(){
return "Howdy, " + this.name;
}
return User;
});
But this results in the User initializer (the User function that accepts the parameter name) being treated like a method with the name Initializer, which is confusing to people trying to use this code.
I've tried adding the #constructor flag, but this has no effect of the html dgeni ends up generating.
Thank you.
UPDATE: Removed references to dgeni. I was under the impression that the plugin I was using (grunt-ngdocs) uses dgeni behind the scenes, but this is not the case.
This is how I would do it not having any experience with Angular in particular:
/**
* #ngdoc service
* #name fooApp.User
* #description User factory.
*/
angular.module('fooApp').factory('User', function(){
/**
* #ngdoc method
* #constructs fooApp.User
* #description Initializes a new User object with a name
*/
function User(name){
this.name = name;
}
User.prototype.greet = function(){
return "Howdy, " + this.name;
}
return User;
});
This is opinionated answer.
I had trouble with Angular documentation, and I even wrote a blog about it, Sigh, AngularJS Documentation
My conclusion was to build a new one. Angular-jsdoc is the outcome.
Here is excerpts from github.
Angular-JSDoc
JSDoc 3 Template for AngularJS.
A JSDoc plugin and template for AngularJS, nothing else!
Features
Right side TOC, table of contents, for navigation by Directives, Services, Controllers, etc
Read and process #ngdoc tag
How Does It Look Like
angularjs-google-maps Documentation
I created a fork/pull request to add #constructor support to gulp-ngdocs as available in grunt-ngdocs: https://github.com/nikhilmodak/gulp-ngdocs/pull/91. All this does is change the basic usage section to include the new keyword.
Then use in a fashion similar to, but slightly different from, #SGD's answer.
Make sure that #ngdoc directive on the service specifies function.
Example:
/**
* #ngdoc function
* #name yourModule.yourService
* #description
*
* Your short description
*
* #constructor
* #param {string} yourConstructorParameter A string paramter
* #returns {Object} An object instance of type YourClassName
*
*/
angular
.module('yourModule', [])
.factory('YourClassName', function() {
/**
* #ngdoc object
* #name yourModule.type:YourClassname
* #description
*
* Short description.
*
*/
function YourClassName(yourConstructorParameter) {
this.yourConstructorParameter = yourConstructorParameter;
this.yourMethod = function() {};
}
/**
* #ngdoc function
* #name yourModule.type:YourClassName#yourPrototypeMethod
* #methodOf yourModule.type:YourClassName
* #description
*
* Short Description.
*
* #returns {Object} The object passed on instantiation.
*/
YourClassName.prototype.yourPrototypeMethod = function() {
return this.yourConstructorParameter;
};
return YourClassName;
});

Documenting a private constructor with JSDoc

I've got a class where individual methods may be called statically but will return a new instance of class in order to chain, for example:
var builder = ns
.setState('a', 'A')
.setState('b', 'B');
Where Builder is defined as such:
/**
* #module Builder
*/
/**
* #class Builder
*/
/**
* #private
*/
function Builder() {
this.state = {
query: {}
};
}
Builder.prototype = {
/**
* #param {string} k - The key
* #param {object} v - The value
* #return {Builder}
*/
setState: function(k, v) {
var that = (this instanceof Builder) ? this : new Builder();
that[k] = v;
return that;
}
// Other properties and methods…
}
The Builder constructor is never supposed to be called explicitly by user code and thus I'd like it not to show up in the docs. However, all of the combinations I've tried with JSDoc tags (e.g. #private, #constructs, etc.) can't seem to suppress it from the built docs.
From version 3.5.0 of jsDoc, you can use tag #hideconstructor on the class, telling jsDoc not to include the constructor into documentation.
/**
* #class Builder
*
* #hideconstructor
*/
function Builder() {
// implementation
}
You should be able to use the #ignore directive to achieve this. From the docs:
The #ignore tag indicates that a symbol in your code should never appear in the documentation. This tag takes precedence over all others.
http://usejsdoc.org/tags-ignore.html

Documentation of classes and modules in YUIDocs

I'm having a bit of trouble writing my documentation for a set of grouped modules. I think it's partly a misconception over what #class, #module and #namespace represent. (Or maybe it's a result of Yahoo trying to shoehorn a 'classical' language vocabulary into JS.)
I've got a roughed out sample below showing how most of my code is written and my attempt at documenting it in YUIDoc-style. The first two parts (Foo and BazManager) are pretty straightforward. To me:
Foo is a #class;
Baz is a #class;
BazManager is a #module (or maybe a #class that contains only #static members);
Qux is also a #module but contains only methods.
My problems are:
If BazManager is a #module, Foo shows up under BazManager;
If BazManager is a #class, the methods inside Baz get sucked into it if you don't add #for to everything;
If BazManager is a #class, then documenting Baz's visibility becomes really tricky;
I really don't know how I'm supposed to document Qux. It seems to me to be a module, but since it has no #classes, it gobbles everything around it, including BazManager. So it must be a #class.
Can anyone suggest how I should be doing this? I don't really care if I get the terms right as long as everything in the documentation gets generated correctly.
Here's my sample code:
// File: Widgets.js
/**
MyNamespace namespace
#namespace MyNamespace
*/
var MyNamespace = window.MyNamespace || {};
//--------------------PART 1: Foo-------------------//
/**
This is a description of Foo.
#class Foo
*/
MyNamespace.Foo = function () {
this.toString = function () {
return "I am a foo";
};
/**
This is Foo's private method description.
#method privateMethod
#private
*/
var privateMethod = function () {};
/**
This is Foo's public method description.
#method publicMethod
*/
this.publicMethod = function () {};
};
//--------------------PART 2: Baz-------------------//
/**
This is a description of BazManager.
#module BazManager
#namespace MyNamespace
*/
MyNamespace.BazManager = (function () {
var self = {};
/**
This is a description of Baz.
#class Baz
*/
var Baz = function (type) {
/**
toString description
#method toString
#returns {String}
*/
this.toString = function () {
return "I am a baz and I'm " + type;
};
};
/**
This is BazManager's privateBaz description.
#method privateBaz
#private
*/
var privateBaz = new Baz("private");
/**
This is BazManager's publicBaz description.
#method publicBaz
*/
self.publicBaz = new Baz("public");
return self;
} ());
//--------------------PART 3: Qux-------------------//
MyNamespace.Qux = (function () {
var self = {};
/**
execute description
#method execute
#private
*/
var execute = function () {
console.log("Qux is done");
};
/**
start description
#method start
*/
self.start = function () {
setTimeout(execute, 1000);
};
return self;
} ());
In YUIDoc #class is used for both classical classes and for objects which contain a bunch of methods. Classes that are meant to be instantiated are also marked with #constructor. That's mostly because of the way that those classes are then shown in the templates. It's a lot easier to track down a class than many lone functions.
The YUI team and many in the community (myself included) seem to be moving away from #namespace. It's hard to get right. Instead we're writing class names with dots in them, ie: #class Plugin.NodeMenuNav.
Modules are meant in the YUI sense and can be mostly understood as "scripts" that contain one or more classes.
So a typical module will look like this:
/**
A series of utilities to do stuff
#module Stuff
**/
/**
A class that does foo very well
#class Foo
#constructor
#param {Object} [config] Configuration object
#param {Boolean} [config.jumpHigh] Whether foo should jump really high
**/
function Foo(config) {
config = config || {};
var high = config.jumpHigh;
}
/**
#method jump
#chainable
**/
Foo.prototype.jump = function () {
// jump
return this;
};
/**
A series of utilities to make Foo do more stuff
#class FooUtils
**/
var FooUtils = {
/**
#method doSomeStuff
#static
**/
doSomeStuff: function () {
}
};
Finally, #for is meant for modules that extend other modules. For instance, you could have a module Bar that adds methods to the prototype of Foo:
/**
Adds extra functionality to Foo
#module Bar
**/
/**
Run really fast
#method run
#for Foo
**/
Foo.prototype.run = function () {};bv

How to document a Require.js (AMD) Modul with jsdoc 3 or jsdoc?

I have 2 types of Modules:
Require.js Main File:
require.config({
baseUrl: "/another/path",
paths: {
"some": "some/v1.0"
},
waitSeconds: 15,
locale: "fr-fr"
});
require( ["some/module", "my/module", "a.js", "b.js"],
function(someModule, myModule) {
}
);
Mediator Pattern:
define([], function(Mediator){
var channels = {};
if (!Mediator) Mediator = {};
Mediator.subscribe = function (channel, subscription) {
if (!channels[channel]) channels[channel] = [];
channels[channel].push(subscription);
};
Mediator.publish = function (channel) {
if (!channels[channel]) return;
var args = [].slice.call(arguments, 1);
for (var i = 0, l = channels[channel].length; i < l; i++) {
channels[channel][i].apply(this, args);
}
};
return Mediator;
});
How can i document this with jsdoc3 when possible with jsdoc too?
This is my first answer on SO, please let me know how I can improve future answers.
Your specific example
I've been searching for an answer for this for a good two days, and there doesn't seem to be a way to document RequireJS AMD modules automatically without some redundancy (like repeated function names). Karthrik's answer does a good job of generating the documentation, but if something gets renamed in the code the documentation will still be generated from what's in the jsDoc tags.
What I ended up doing is the following, which is adjusted from Karthik's example. Note the #lends tag on line 1, and the removal of the #name tag from the jsDoc comment blocks.
define([], /** #lends Mediator */ function(Mediator){
/**
* Mediator class
* This is the interface class for user related modules
* #class Mediator
*/
var channels = {};
if (!Mediator) Mediator = {};
/**
* .... description goes here ...
* #function
*
* #param {Number} channel .....
* #param {String} subscription ..............
* #example
* add the sample code here if relevent.
*
*/
Mediator.subscribe = function (channel, subscription) {
if (!channels[channel]) channels[channel] = [];
channels[channel].push(subscription);
};
Mediator.publish = function (channel) {
if (!channels[channel]) return;
var args = [].slice.call(arguments, 1);
for (var i = 0, l = channels[channel].length; i < l; i++) {
channels[channel][i].apply(this, args);
}
};
return Mediator;
});
From what I understand, the #lends tag will interpret all jsDoc comments from the next following object literal as part of the class referenced by the #lends tag. In this case the next object literal is the one beginning with function(Mediator) {. The #name tag is removed so that jsDoc looks in the source code for function names, etc.
Note: I've used the #exports tag at the same place as where I put the #lends tag. While that works, it'll create a module in the docs… and I only wanted to generate docs for the class. This way works for me!
General jsDoc references
jsdoc-toolkit Tag Reference - Great reference for the tags in jsdoc-toolkit. Has a bunch of examples, too!
2ality's jsDoc intro - Comprehensive tutorial based on jsDoc-toolkit.
jsDoc3 reference - Fairly incomplete, but has some examples.
jsDoc doesn't seem to like the "define" and "require" calls.
So, we ended up using multiple tags to make the jsDoc tool to pick up the constructor and other specific class methods. Please have a look at the example below:
I have just copy-pasted from my source-code and replaced it with your class name and method names. Hope it works for you.
define([], function(Mediator){
/**
* Mediator class
* This is the interface class for user related modules
* #name Mediator
* #class Mediator
* #constructor
* #return Session Object
*/
var channels = {};
if (!Mediator) Mediator = {};
/**
* .... description goes here ...
* #name Mediator#subscribe
* #function
*
* #param {Number} channel .....
* #param {String} subscription ..............
* #example
* add the sample code here if relevent.
*
*/
Mediator.subscribe = function (channel, subscription) {
if (!channels[channel]) channels[channel] = [];
channels[channel].push(subscription);
};
Mediator.publish = function (channel) {
if (!channels[channel]) return;
var args = [].slice.call(arguments, 1);
for (var i = 0, l = channels[channel].length; i < l; i++) {
channels[channel][i].apply(this, args);
}
};
return Mediator;
});
Note: The above method of documenting JS-code worked out well for us while using jsDoc. Haven't got a chance to try jsDoc3.
Taking the link from Muxa's answer, we see that the documentation does specifically refer to RequireJS:
The RequireJS library provides a define method that allows you to write a function to return a module object. Use the #exports tag to document that all the members of an object literal should be documented as members of a module.
Module Example
define('my/shirt', function () {
/**
* A module representing a shirt.
* #exports my/shirt
* #version 1.0
*/
var shirt = {
/** A property of the module. */
color: "black",
/** #constructor */
Turtleneck: function(size) {
/** A property of the class. */
this.size = size;
}
};
return shirt;
});
So in the above example, we see that jsdoc will parse a my/shirt module and document it as having two members: a property color, and also a class Turtleneck. The Turtleneck class will also be documented as having it's own property size.
Constructor Module Example
Use the #alias tag simplify documenting a constructor-module in RequireJS.
/**
* A module representing a jacket.
* #module jacket
*/
define('jacket', function () {
/**
* #constructor
* #alias module:jacket
*/
var exports = function() {
}
/** Open and close your Jacket. */
exports.prototype.zip = function() {
}
return exports;
});
The above is what you'd want to use if you are exporting a constructor function as the module which will be used as a class to instantiate objects. To sum up, I'm not sure about using the #lends and other tags/techniques that have been recommended. Instead, I would try to stick with the #module, #exports, and #alias tags used in the documentation referencing RequireJS.
I'm not sure how you should document your requirejs 'main' file. If I understand correctly, you are not actually defining any module there, but rather executing a one off function which depends on several modules.
My AMD classes use a slightly different form, but JSDoc wasn't documenting them either so I thought I'd share what worked for me.
Constructors in the global namespace are automatically added:
/**
* #classdesc This class will be documented automatically because it is not in
* another function.
* #constructor
*/
function TestClassGlobal() {
/**
* This is a public method and will be documented automatically.
*/
this.publicMethod = function() {
};
}
If you want this behavior on a constructor inside an AMD module, declare it either as global or a member of a namespace:
define([], function() {
/**
* #classdesc This won't be automatically documented unless you add memberof,
* because it's inside another function.
* #constructor
* #memberof Namespace
*/
function TestClassNamespace() {
}
/**
* #classdesc This won't be automatically documented unless you add global,
* because it's inside another function.
* #constructor
* #global
*/
function TestClassForcedGlobal() {
}
});
Looks like things have gotten a lot simpler in JSDoc3. The following worked for me:
Mediator as a module
/**
* Mediator Module
* #module Package/Mediator
*/
define([], function(Mediator){
var channels = {};
if (!Mediator) Mediator = {};
/**
* Subscribe
* #param {String} channel Channel to listen to
* #param {Function} subscription Callback when channel updates
* #memberOf module:Package/Mediator
*/
Mediator.subscribe = function (channel, subscription) {
if (!channels[channel]) channels[channel] = [];
channels[channel].push(subscription);
};
/**
* Publish
* #param {String} channel Channel that has new content
* #memberOf module:Package/Mediator
*/
Mediator.publish = function (channel) {
if (!channels[channel]) return;
var args = [].slice.call(arguments, 1);
for (var i = 0, l = channels[channel].length; i < l; i++) {
channels[channel][i].apply(this, args);
}
};
return Mediator;
});
However, I would probably make the following change to the code:
/**
* Mediator Module
* #module Package/Mediator
*/
define([], function(){
var channels = {};
var Mediator = {}
...
Reason is, the module says it defines Mediator, but seems to borrow from some other instance of Mediator. I'm not sure I understand that. In this version, it's clear Mediator is defined by this file and exported.

Categories

Resources