Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jsdoc not documenting properly nodejs modules

Tags:

node.js

jsdoc

I'm trying to get JSDOC (3) to properly document my NodeJS modules. While simple modules work, I can't find the way to document a slightly more complex module.

My NodeJS module has the following structure:

/** @module MyModule */
(function() {


     function functionToExportOne {...}

     function functionToExportTwo {...}

     /** 
      * @module MyModule.ClassToExportOne
      * @constructor 
      */
     function ClassToExportOne {

           this.classMethodOne=function() { ... }
           this.classMethodTwo=function() { ... }

     }

     /** @constructor */
     function ClassToExportTwo {

           function classMethodOne() { ... }
           function classMethodTwo() { ... }

           return /** @lends {ClassToExportTwo.prototype} */ {

               methodOne:classMethodOne,
               methodTwo:classMethodTwo
           }
     }
     /** @exports MyModule */  <--- late addition, see comments
     module.exports={
         functionOne:functionToExportOne,
         functionTwo:functionToExportTwo,
         classOne:ClassToExportOne,
         classTwo:ClassToExportTwo
     }
})()

Well, as you see, the module exports both methods and class constructors. Nothing very strange.

The problem is, JSDOC

  • always fails to recognize the inner classes,
  • Mistakes the first inner class methods as the (outer) module's methods,
  • always skips the real exported module methods.
  • The closest I've been is, in ClassToExportOne, when I use @module MyModule.<className> followed by @constructor (in this order) : In this case the class is recognized, but only the constructor is documented, and its methods are documented as belonging to the parent module

I've tried thousands of different combinations without success:

  • defining inner classes methods with this.method=function() {...} (as depicted in ClassToExportOne) or returning an object with methods using @lends {ClassToExportTwo.prototype} (as depicted in ClassToExportTwo)
  • using @module MyModule.ClassToExportOne in the header of each class
  • defining module.exports vs exports.xxxx
  • declaring inner classes @private, declaring everything @private but the exports
  • moving @module declaration to just before the first exports (total mess then, some stuff gets promoted to "global" even though it's inside the main closure!!)
  • if I add @exports <modulename> just before the exports declaration, the methods are documented (mixed with the class methods)

I've tried everything suggested in http://usejsdoc.org/howto-commonjs-modules.html without success.

I'm sure I'm missing something, but can't find what.

like image 247
rupps Avatar asked Jun 09 '15 21:06

rupps


2 Answers

The following works for me with jsdoc 3.3.3:

/**
 * Example model.
 *
 * @module model/example
 */
module.exports = (function () {
    /**
     * Constructor function.
     *
     * @exports model/example.Example
     * @constructor
     * @param {string} id
     */
    var example = function Example(id) {
        this.id = id;
    };

    /**
     * Returns the ID.
     *
     * @memberof model/example.Example
     * @returns {string} the id
     */
    example.prototype.getId = function () {
        return this.id;
    };

    return example;
}());

and an example creating an instance of the model:

var example = new Example("ID");
console.log(example.getId());
like image 76
DJDaveMark Avatar answered Sep 28 '22 07:09

DJDaveMark


I hate to answer my own question, but with a little more trial and error I got quite satisfactory results. Please feel free to comment if this is a correct approach, but the fact is the documentation is now properly generated :)

The key seems to be to use @exports <modulename>.<classname> before @constructor , this way the class appear in the index under "classes", and with its methods properly documented IF the methods are declared with this.method=function() {...}

I still would like to find a way to make this work, if at all possible, for the case depicted in ClassToExportTwo , sometimes it's very convenient for me to define a class like this, specially for long classes that call private methods so I can avoid totally using "this" inside the class (optimization).

Well here's the template that works for me:

/** @module MyModule */
(function() {


     function functionToExportOne {...}

     function functionToExportTwo {...}

     /** works !!
      * @exports MyModule.ClassToExportOne
      * @constructor 
      */
     function ClassToExportOne {

           function innerMethod() { ... }

           // this works: assigning methods to this

           this.classMethodOne=function() { ... }
           this.classMethodTwo=function() { ... }

     }

     /** does not work
      * @exports MyModule.ClassToExportTwo
      * @constructor 
      */         
     function ClassToExportTwo {

           function classMethodOne() { ... }
           function classMethodTwo() { ... }

           // this DOES NOT WORK !! Methods get mixed with parent module
           return  {

               methodOne:classMethodOne,
               methodTwo:classMethodTwo
           }
     }

     // no more @exports here as it duplicates definitions in the docs
     module.exports={
         /** blah blah function description */
         functionOne:functionToExportOne,
         /** blah blah function description */
         functionTwo:functionToExportTwo,
         /** blah blah function description */
         classOne:ClassToExportOne,
         /** blah blah function description */
         classTwo:ClassToExportTwo
     }
})()
like image 45
rupps Avatar answered Sep 28 '22 09:09

rupps