I have the following JavaScript.
It is a RequireJS module that has its functions namespaced into an object literal. I referred to: How do I JSDoc A Nested Object's Methods? to find out how to mark up the JSDoc notations.
I run JSDocs 3.3.0-beta3 with private: true in a grunt task but on the modules page there are no private methods or arguments for the publich method.
/**
* A module doing a lot of Foo.
* #module Foo
* #requires jquery
* #author Markus Falk
*/
define(['jquery'], function($) {
'use strict';
/**
* #property {Object} Container
*/
var Foo = {
/**
* Caches all jQuery Objects for later use
* #function
* #private
*/
_cacheElements: function() {
this.$foo = $('.foo');
},
/**
* inits the app and returns the Message Text
* #function
* #public
* #param {Object} msg - The message.
* #param {string} msg.text - The message's Text.
* #param {string} msg.author - The message's author.
* #returns {String} Sentence with given message.text
*/
init: function(msg) {
this._cacheElements();
return "Say " + msg.text;
}
};
return /** #alias module:Foo */ {
/** init */
init: Foo.init
};
});
Here is the output of this JSDoc code:
Try #function init and #function _cacheElements
/**
* A module representing a Foo.
* #module Foo
* #requires jquery
* #author Markus Falk
*/
define(['jquery'], function($) {
'use strict';
/**
* #property {Object} Container
*/
var Foo = {
/**
* Caches all jQuery Objects for later use
* #function _cacheElements
* #private
*/
_cacheElements: function() {
this.$foo = $('.foo');
},
/**
* inits the app and returns the Message Text
* #function init
* #public
* #param {Object} msg - The message.
* #param {string} msg.text - The message's Text.
* #param {string} msg.author - The message's author.
* #returns {String} Sentence with given message.text
*/
init: function(msg) {
this._cacheElements();
return "Say " + msg.text;
}
};
return /** #alias module:Foo */ {
/** init */
init: Foo.init
};
});
If I define an object like this:
/**
* My Cool Object
* #constructor
*/
function MyCoolObject() {
/**
* Cool Method, private
* #param {!string} parameter
*/
function localMethod(parameter) {
// do stuff
}
// Export the method
this.exportedMethod = localMethod;
}
I'd like to know, if at all possible, how to tell JSDOC to use the annotation for localMethod in exportedMethod, or how can I annotate exportedMethod, because if I do:
// Export the method
/**
* Cool Method
* #param {!string} parameter
*/
this.exportedMethod = localMethod;
JSDOC assumes it's a field rather than a method, then only uses the description, ignoring the #param part.
I would reduce it to:
/**
* My Cool Object
* #constructor
*/
function MyCoolObject() {
/**
* Cool Method, private
* #param {!string} parameter
*/
this.exportedMethod = function (parameter) {
// do stuff
};
}
You can do var localMethod = this.exportedMethod right after if you want a local reference to the method. In the off chance that you've over-simplified your example and you need to first assign to localMethod before assigning to this.exportedMethod you could do this:
/**
* My Cool Object
* #constructor
*/
function MyCoolObject() {
function localMethod(parameter) {
// do stuff
}
/**
* Cool Method, private
* #param {!string} parameter
* #function
*/
// Export the method
this.exportedMethod = localMethod;
}
The #function declaration tells jsdoc that it is dealing with a function.
I'm trying to create documentation based on the following structure:
/**
* #ngdoc service
*
* #name module:resource
* #module module
* # return {Object} The returned object
*/
angular.module('module').factory('resource', [
function () {
function Foo (param1) {
//Do something with param1
}
return {
Test: {
/**
* #ngdoc function
* #name resource#theTest
* #methodOf module:resource
*
* #description
* Search to see if a study exists with the given protocol identifier
* #param {Object} params The param
* #return {Object} A Promise
*/
theTest: function(param) {
return functionFoo (param);
},
/**
* #ngdoc function
* #name resource#theTest1
* #methodOf module:resource
*
* #description
* Search to see if a study exists with the given protocol identifier
* #param {Object} params The param
* #return {Object} A Promise
*/
theTest1: function(param) {
return functionFoo (param)
}
}
};
}
]);
What I would like to say in the documentation is that the service 'resource' returns an object that returns a collection of functions, but I cannot find the way of doing this with ngdocs. Is it supported?
Thank you
I don't think you could specify a 'map of function' the only type that are supported are Function, object, string, number, ...
But you could instead add a description in your class like:
/*
* #description
* This class return 2 functions as describe below:
* ```js
* {
* theTest {Function} This function do (...)
* theTest1 {Function} This function do (...)
* };
* ```
*/
function Foo (param1) {
Hope this will help
Let's say we are constructing a nested namespace where we will be prototyping multiple objects as needed. By default the object window.blah.foo is empty. We then prototype all the sub-objects and their functions in a single prototype. When documenting as we have below we show all the inner functions as globals. Now imagine you have dozens of files built this same way. How might we document this so that the .bar1(), bar2(), and bar3() functions are methods of the window.blah.foo object, especially when its instantiation occurs outside this file, possibly multiple times.
/**
* Blah - Our very own global Namespace
* #namespace
* #type {object}
* #global
* #public
*/
window.blah = window.blah || {};
/**
* Immediately-Invoked Function Expression (IIFE).
* #function
* #param {object} w - Global window object.
* #returns {Object} window.blah.foo
*/
(function (w) {
// strict JS
'use strict';
/**
* Create instance of w.blah.foo constructor
* #constructor
*/
w.blah.foo = function () {
};
/**
* Append properties and methods to an instance of window.blah.foo
* #constructor
*/
w.blah.foo.prototype = {
/**
* Dummy function to return the number 1.
* #method bar1
*/
bar1: function () {
console.log(1);
},
/**
* Dummy function to return the number 2.
* #method bar2
*/
bar2: function () {
console.log(2);
},
/**
* Dummy function to return the number 3.
* #method bar3
*/
bar3: function () {
console.log(3);
}
};
}(window));
The following will move the barX methods where they belong. Note that there's nothing for jsdoc to do with the doclet that documents the IIFE. The key to get the methods in the right place is /** #lends blah.foo# */. See the documentation of the #lends. The # tells jsdoc that the items lent to blah.foo belong to an instance of the class. See the documentation on namepaths for more details.
/**
* Blah - Our very own global Namespace
* #namespace
* #global
*/
window.blah = window.blah || {};
/**
* Immediately-Invoked Function Expression (IIFE).
* #function
* #param {object} w - Global window object.
* #returns {Object} window.blah.foo
*/
(function (w) {
// strict JS
'use strict';
/**
* Create instance of w.blah.foo constructor
* #constructor
* #name blah.foo
*/
w.blah.foo = function () {
};
/** #lends blah.foo# */
w.blah.foo.prototype = {
/**
* Dummy function to return the number 1.
*/
bar1: function () {
console.log(1);
},
/**
* Dummy function to return the number 2.
*/
bar2: function () {
console.log(2);
},
/**
* Dummy function to return the number 3.
*/
bar3: function () {
console.log(3);
}
};
}(window));
I've been trying to use JSDoc3 to generate documentation on a file, but I'm having some difficulty. The file (which is a Require.js module) basically looks like this:
define([], function() {
/*
* #exports mystuff/foo
*/
var foo = {
/**
* #member
*/
bar: {
/**
* #method
*/
baz: function() { /*...*/ }
}
};
return foo;
}
The problem is, I can't get baz to show up in the generated documentation. Instead I just get a documentation file for a foo/foo module, which lists a bar member, but bar has no baz (just a link to foo's source code).
I've tried changing bar's directive to #property instead, and I've tried changing baz's directive to #member or #property, but none of that helps. No matter what I do, baz just doesn't seem to want to show up.
Does anyone know what directive structure I could use to get baz to appear in the generated documentation?
P.S. I've tried reading pages like this one on the JSDoc site http://usejsdoc.org/howto-commonjs-modules.html, but it only describes cases of foo.bar, not foo.bar.baz.
You can use a combination of #module or #namespace along with #memberof.
define([], function() {
/**
* A test module foo
* #version 1.0
* #exports mystuff/foo
* #namespace foo
*/
var foo = {
/**
* A method in first level, just for test
* #memberof foo
* #method testFirstLvl
*/
testFirstLvl: function(msg) {},
/**
* Test child object with child namespace
* #memberof foo
* #type {object}
* #namespace foo.bar
*/
bar: {
/**
* A Test Inner method in child namespace
* #memberof foo.bar
* #method baz
*/
baz: function() { /*...*/ }
},
/**
* Test child object without namespace
* #memberof foo
* #type {object}
* #property {method} baz2 A child method as property defination
*/
bar2: {
/**
* A Test Inner method
* #memberof foo.bar2
* #method baz2
*/
baz2: function() { /*...*/ }
},
/**
* Test child object with namespace and property def.
* #memberof foo
* #type {object}
* #namespace foo.bar3
* #property {method} baz3 A child method as property defination
*/
bar3: {
/**
* A Test Inner method in child namespace
* #memberof foo.bar3
* #method baz3
*/
baz3: function() { /*...*/ }
},
/**
* Test child object
* #memberof foo
* #type {object}
* #property {method} baz4 A child method
*/
bar4: {
/**
* The #alias and #memberof! tags force JSDoc to document the
* property as `bar4.baz4` (rather than `baz4`) and to be a member of
* `Data#`. You can link to the property as {#link foo#bar4.baz4}.
* #alias bar4.baz4
* #memberof! foo#
* #method bar4.baz4
*/
baz4: function() { /*...*/ }
}
};
return foo;
});
EDIT as per Comment: (Single page solution for module)
bar4 without that ugly property table. ie #property removed from bar4.
define([], function() {
/**
* A test module foo
* #version 1.0
* #exports mystuff/foo
* #namespace foo
*/
var foo = {
/**
* A method in first level, just for test
* #memberof foo
* #method testFirstLvl
*/
testFirstLvl: function(msg) {},
/**
* Test child object
* #memberof foo
* #type {object}
*/
bar4: {
/**
* The #alias and #memberof! tags force JSDoc to document the
* property as `bar4.baz4` (rather than `baz4`) and to be a member of
* `Data#`. You can link to the property as {#link foo#bar4.baz4}.
* #alias bar4.baz4
* #memberof! foo#
* #method bar4.baz4
*/
baz4: function() { /*...*/ },
/**
* #memberof! for a memeber
* #alias bar4.test
* #memberof! foo#
* #member bar4.test
*/
test : true
}
};
return foo;
});
References -
Another Question about nested namespaces
For alternative way of using Namespaces
Documenting literal objects
*Note I haven't tried it myself. Please try and share the results.
Here's a simple way to do it:
/**
* #module mystuff/foo
* #version 1.0
*/
define([], function() {
/** #lends module:mystuff/foo */
var foo = {
/**
* A method in first level, just for test
*/
testFirstLvl: function(msg) {},
/**
* #namespace
*/
bar4: {
/**
* This is the description for baz4.
*/
baz4: function() { /*...*/ },
/**
* This is the description for test.
*/
test : true
}
};
return foo;
});
Note that jsdoc can infer the types baz4.baz4 and test without having to say #method and #member.
As far as having jsdoc3 put documentation for classes and namespaces on the same page as the module that defines them, I don't know how to do it.
I've been using jsdoc3 for months, documenting a small library and a large application with it. I prefer to bend to jsdoc3's will in some areas than have to type reams of #-directives to bend it to my will.
You can't document nested functions directly. I didn't like Prongs solution, so I used a different implementation without namespaces (it's JS, not Java!).
Update:
I updated my answer to reflect the exact use case given by the OP (which is fair, since JSdoc is pretty painful to use). Here is how it would work:
/** #module foobar */
/** #function */
function foobarbaz() {
/*
* You can't document properties inside a function as members, like you
* can for classes. In Javascript, functions are first-class objects. The
* workaround is to make it a #memberof it's closest parent (the module).
* manually linking it to the function using (see: {#link ...}), and giving
* it a #name.
*/
/**
* Foo object (see: {#link module:foobar~foobarbaz})
* #name foo
* #inner
* #private
* #memberof module:foobar
* #property {Object} foo - The foo object
* #property {Object} foo.bar - The bar object
* #property {function} foo.bar.baz - The baz function
*/
var foo = {
/*
* You can follow the same steps that was done for foo, with bar. Or if the
* #property description of foo.bar is enough, leave this alone.
*/
bar: {
/*
* Like the limitation with the foo object, you can only document members
* of #classes. Here I used the same technique as foo, except with baz.
*/
/**
* Baz function (see: {#link module:foobar~foo})
* #function
* #memberof module:foobar
* #returns {string} Some string
*/
baz: function() { /*...*/ }
}
};
return foo;
}
Unfortunately JSdoc is a port of Java, so it has a lot of features that make sense for Java but not for JS, and vice-versa. For example, since in JS functions are first-class objects, they can be treated as objects or functions. So doing something like this should work:
/** #function */
function hello() {
/** #member {Object} */
var hi = {};
}
But it won't, because JSdoc recognizes it as a function. You would have to use namespaces, my technique with #link, or to make it a class:
/** #class */
function Hello() {
/** #member {Object} */
var hi = {};
}
But then that doesn't make sense either. Do classes exist in JS? no, they don't.
I think we really need to find a better documentation solution. I've even seen inconsistencies in the documentation for with how types should be displayed (e.g. {object} vs {Object}).
You can also use my technique to document closures.
Just to improve on Prongs's answer a bit for JSDoc3, I was only able to get it to work when I used the #instance annotation in lieu of #member.
ES6 example code follows:
class Test
{
/**
* #param {object} something
*/
constructor(something)
{
this.somethingElse = something;
/**
* This sub-object contains all sub-class functionality.
*
* #type {object}
*/
this.topology = {
/**
* Informative comment here!
*
* #alias topology.toJSON
* #memberof! Test#
* #instance topology.toJSON
*
* #returns {object} JSON object
*/
toJSON()
{
return deepclone(privatesMap.get(this).innerJSON);
},
...
}
}
}