DEV Community

Marko V
Marko V

Posted on

How to increase your CoQ.

Code Quality. What did you think it meant?

I've already written about linting, unit-testing is another and documentation is a third. JSDoc is one way to keep track of things. If you haven't encountered it before, it's a structured way to maintain your in-line comments and make use of it as a documentation tool. You can express the in's and out's of functions, what their usage is, their limitations and dependencies. You can define your modules and classes.. and finally, you can generate an interactive documentation site based on your comments.

So to get started it's quite simple. In Visual Studio, and VS Code, you can start to type "/**" and it will auto-complete the beginnings of a JSDoc entry if it's a .js file. If you do it above the line of a function definition, and you press enter it will auto-complete the parameters for you and all you need to do is add typing (unless that is already clearly defined and the IDE can detect it) and the usage of the parameter.

So to start documenting your code, it kind of looks like this;

Sample

/**
 * Localization Service for angular
 * @exports services/localeService
 * @param {NgModule} $http injection of the AngularJS native $http module (supplies access to XHR requests)
 * @param {NgModule} $window injection of the AngularJS native $window module (supplies access to the window object)
 * @param {NgModule} $q injection of the AngularJS native $q module (supplies promises)
 * @param {NgModule} $cookies injection of the AngularJS native $cookies module (supplies access to cookies)
 * @returns { function } a localeService singleton
 */

@exports defines what this file/function exports/relates to in terms of modules. This one in particular is a part of the shared service modules and is called localeService
@param is quite clear. It defines one of the parameters, what type it is, it's name and what it is used for.
@returns just states the return type and what it contains.

Ok, so now that you've documented everything, well... atleast something, you can now run jsdoc command-line tool to generate the documentation site.

First, install the jsdoc tool

npm i jsdoc -g

Next add a jsdoc config file, you can name it whatever you want, I named mine jsdoc.conf.json

{
  "plugins": [ "plugins/markdown" ],
  "recurseDepth": 10,
  "source": {
    "includePattern": ".+\\.js(doc|x)?$",
    "excludePattern": "(^|\\/|\\\\)_|.+es5.js|.+es2015.js|JsonEditor.js|angular.js|angular-cookies.js|angular-mocks.js|angular-sanitize.js"
  },
  "sourceType": "module",
  "tags": {
    "allowUnknownTags": true,
    "dictionaries": [ "jsdoc", "closure" ]
  },
  "templates": {
    "cleverLinks": false,
    "monospaceLinks": false
  }
}

Next, run the command-line tool. All of our scripts are contained in a hierarchy inside the Scripts folder of our web application, so this is the line I ran.

jsdoc Scripts --recurse -c jsdoc.conf.json

And voilá... a nice documentation site is now available in the output path (which you can change btw). Default an "out" folder is created in the working directory you run this command from.

JSDoc Site

References;

Full Example (with redacted code blocks)

/**
 * Localization Service for angular
 * @exports services/localeService
 * @param {NgModule} $http injection of the AngularJS native $http module (supplies access to XHR requests)
 * @param {NgModule} $window injection of the AngularJS native $window module (supplies access to the window object)
 * @param {NgModule} $q injection of the AngularJS native $q module (supplies promises)
 * @param {NgModule} $cookies injection of the AngularJS native $cookies module (supplies access to cookies)
 * @returns { function } a localeService singleton
 */
function localeService($http, $window, $q, $cookies) {
    'use strict';
    var self = this;
    /**
     * Function to find out which locale is relevant for the user and if we support it.
     * @returns { string } A string representing the localization moniker.
     * */
    this.resolveBrowserLocale = function () {
      // ... redacted ...
    };
    /**
     * Initialization function that tries to get the current list of valid translations provided by a service
     * @returns { Promise } A promise that contains the translations
     * */
    this.init = function () {
      // ... redacted ...
    };
    /**
     * Waits for the resolution of the translations to retrieve an entry from the resultset.
     * @param { string } entry representing the dotannotated path to lookup a translation for.
     * @param { boolean } debug a true/false value to whether or not output debug data in the console.
     * @returns { Promise } A promise containing the attempted lookup. If it fails to find it, it will return the string provided in entry.
     */
    this.getEntry = function (entry, debug) {
        return $q(function (resolve, reject) {
          // ... redacted ...
        });
    };
    /**
     * A complex function to do translation lookup based on the provided object and property to do lookup on. Multiple paths of execution.
     * @param {any} obj Object that contains values to translate
     * @param {string} propToRepl If provided, it will attempt to do lookup on this property and replace it's content before returning the modified object.
     * @param {string} propToLookUp If provided, it will attempt to do lookup on this property-value compounded with propToRepl and insert the found value in propToRepl
     * @param {boolean} tdebug true/false if truthy it will log data to console.
     * @returns { any } The modified object is returned.
     */
    this.translateObject = function (obj, propToRepl, propToLookUp, tdebug) {
      //... redacted ...        
    };
    /**
     * Internal logger function
     * @param {any} obj Object to inject to console.log
     * @param {any} logthis if defined at all, it will use it as a truthy value and output data to console.
     * @returns {void} It outputs data to console. It has no return value.
     */
    this.logger = function (obj, logthis) {
      // ... redacted ...
    };
    /**
     * Lookup helper function, not intended for external consumption/usage.
     * @param {string} dotValue Lookup value to find.
     * @param {any} logThis if defined, it will log data through the private logger function.
     * @returns {string} A translated string or the original string
     */
    this.getDotAnnotatedValue = function (dotValue, logThis) {
      // ... redacted ...
    };
    /** A promise that contains the initialization status of the singleton and it's returned value */
    this.initialized = this.init();
    this.initialized.then(function (data) { self.data = data; });
    return this;
}
/** Injects the localeService into the angular module myAteaApp.services for others to consume */
angular.module('myApp.services').factory('localeService', ['$http', '$window', '$q', '$cookies', localeService]);

Tags: https://jsdoc.app/index.html#block-tags
Getting started: https://jsdoc.app/about-getting-started.html

Top comments (0)