9

In order to avoid using new in my JavaScript code, I write factories to create objects.

I have tried many combinations and the one that gives me the most satisfactory result is the following:

/**
 * Document module
 * @module app/document
 */
(function () {
    'use strict';

    /**
     * Factory that creates a document object.
     * @alias module:app/document.factory
     * @return {document}
     */
    function document() {
        /**
         * Get document id
         * @method id
         * @return {String}
         */
        var id = function id() {...},
            api = {
                id: id
            };

        return api;
    }

    /**
     * This module exports the {@link module:app/document.factory|factory} function.
     */
    module.exports = document;
}());

The problem with these comments is there is no document object defined. Therefore, I can't reference this object in another object and I can't inherit its documentation when I extends this object.

What is the appropriate way to document this kind of object?

If I use the @typedef tag, I get the static factory method and the document object properly documented but no id method documentation is generated by JSDoc:

/**
 * Document module.
 * @module app/document
 */
(function () {
    'use strict';

    /**
     * Factory that creates a document object.
     * @function module:app/document.factory
     * @return {document}
     */
    function factory(agent) {
        /**
         * @callback document~id
         * @returns {String}
         */
        var id = function id() {...},

            /**
             * @typedef document
             * @property {document~id} id
             */
            document = {
                id: id
            };

        return document;
    }

    module.exports = factory;
}());
goriol
  • 91
  • 5
  • try not yo use reserved keywords as document or id for functions – Sagi Sep 13 '15 at 09:36
  • use @typedef - This will allow you to reference it – elad.chen Sep 13 '15 at 09:39
  • @elad.chen I edited the question to try with `@typedef`, but I don't get the expected result. – goriol Sep 13 '15 at 10:31
  • @Sagi I don't understand your remark as neither `id` nor `document` are reserved words in JavaScript. – goriol Sep 13 '15 at 10:32
  • it depends where you put them in case you put it in the global scope you'll get "Uncaught TypeError: Identifier 'document' has already been declared". Just a remark that is not related to your problem. – Sagi Sep 13 '15 at 10:39
  • I didn't get that error on Chrome. I would only use document as a var in node though, to reduce confusion with new developers. –  Apr 19 '18 at 18:44

2 Answers2

1

My recommendation to you is to well define the exports on your module using @typedef to define the type and then annotate the module.exports = factory with @type {FactoryDefinition}

 /** @typedef {{ id: !string }} */
 var DocumentDefinition;

 /** @typedef {!function(!object):!DocumentDefinition} */
 var FactoryDefinition;

/** @type {FactoryDefinition} */
module.exports = factory
Sagi
  • 8,972
  • 3
  • 33
  • 41
1

I always use a @typedef outside my module wrapper where I summarise the complete set of functions exposed by the module. This is the only way I managed to get code completion in my WebStorm IDE and generate useful HTML documentation.

/** @namespace SharedLib */

/**
 * @typedef SharedLib.PriorityQueueFactory
 * @function
 * @template T
 * @param {function(T, T): Boolean} comparator Comparison function like for <code>Array.prototype.sort</code>
 * @return {{pop: function(Array<T>): Array<Array<T>| T>, push: function(Array<T>, T): Array<T>}} an object containing the functions to manage the queue
 */

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define([], factory);
    }
    else if (typeof module === 'object' && module.exports) {
        module.exports = factory();
    }
    else {
        root.returnExports = factory();
    }
}(typeof self !== 'undefined' ? self : this,
    function () {

        /** @type {SharedLib.PriorityQueueFactory} */
        function priorityQueueFactory(comparator) {
            const
                push = function(queue, item) {
                    const
                        clonedQueue = queue.slice();
                    clonedQueue.push(item);

                    return clonedQueue.sort(comparator);
                },
                // ...
            return {
                push: push,
                pop: pop
            };
        }

        return priorityQueueFactory;
}));

The generated docs look like this.

Semmel
  • 1,040
  • 10
  • 14