Chai Coding Style Guide

Jake Luer edited this page Aug 29, 2014 · 9 revisions

These "style guidelines" are used to keep the Chai codebase clean and consistent.

Recent updates are different from Chai's current codebase. As Chai is rewritten approaching its next major release these styles will be applied.

Basics

  • Spaces as Tabs using width of 2 spaces
  • Use semicolons
  • Max line-length of 80 characters.
  • Functions that are constructors are capitalized. Private functions or prototype methods are camelCase.

Variable Declarations

Variable should be declared when needed. Each variable line has a var associated with it.

Previously this was one var per block of declarations.

var hello = require('hello');
var universe = require('universe');

Furthermore, declarations should be declared in alphabetical order whenever possible. The exception is if a declaration requires a previous declaration. For example...

var hello = require('hello');
var path = require('path');
var join = path.join // helper;
var universe = require('universe');

Finally, file-wide declarations should be grouped by the context of their origin. The following order should be observed.

  • external dependencies
  • local constructors
  • local utilities
  • constants
/*!
 * External Dependencies
 */

var fs = require('fs');
var path = require('path');

/*!
 * Local Constructors
 */

var Bar = require('./bar');
var Foo = require('./foo');

/*!
 * Local Dependencies
 */

var ping = require('./common/ping')
var pong = require('./common/pong');

/*!
 * Module Constants
 */

var GENRES = [ 'rock', 'classical', 'jazz' ];
var VOLUME = 'loud';

Objects and Arrays

Objects and Arrays are simple.

var obj = {
  hello: 'universe', 
  ping: 'pong',
  genres: [
    'rock',
    'classical',
    'jazz'
  ],
  volume: {
    loud: 10,
    medium: 5,
    soft: 2
  }
};

If you are using objects or arrays inline or it is a short declaration, you may list them on one line provided the line length doesn't violate standards and there is no nesting of other objects or arrays. If you do, use spaces after the first and before the last bracket.

var GENRES = [ 'rock', 'classical', 'jazz' ];

cb(null, { hello: 'universe', ping: 'pong' });
cb(null, [ 'rock', 'classical', 'jazz' ]);

Function Declarations

Spacing

Function declarations always have a space after the param declarations.

Previously this was a space before and after.

function doSomething(err, cb) {
  // ...
}

Naming

Inline async callback function do not require names, but functions that are a return do.

ee.on('event', function(args) {
  // ...
});

function middleware(spec) {
  return function handleMiddleware(req, res) {
    // ...
  };
}

Documentation

Inline documentation blocks are required for all top level function, methods or property definitions. They closely resemble jsdocs format. As these are parsed as markdown there should be a header, a description, and optional code samples and bulleted list of options. Furthermore, there should be an empty line before and after each comment block.

Headers

Constructor headers are an H3 whereas prototype methods and property headers are an H4. Arguments should be listed with optional arguments in brackets [ and ]. Methods start with a ..

Headers are not required for functions or methods that are intended to be private (not exported for documentation).

/**
 * #### .doSomething([param,] cb)
 *

Code Samples

Code samples are expected to be parsed using GitHub Flavored Markdown. Code samples are not required but advised if clarification is needed. Furthermore, should not be included for private API functions/methods.

 * ```js
 * something.doSomething('universe', function (err, result) {
 *   // ...
 * });
 * ```

Params

The following @ declarations are required.

  • @param for each parameters a function uses in the format of @param {Type|Type2} short description
  • @api can be either public or private.

Optionally, the following should be included if conditions apply.

  • @name is used to name the method for documentation lists in the format of @name doSomething.
  • @return if the function returns a value. Use format @return {String} short description
  • @ctx if function needs to be called with the context of a specific constructor. Use format @ctx Constructor
  • @cb if the function is asynchronous. One line for each parameter in a callback, listed in order using the format @cb {Error|null} if error or @cb {String} result of said action.
Public Example (visible in docs)
/**
 * ### Something(opts)
 *
 * Construct a something.
 *
 * Options
 * - `bar` _{Boolean}_ toggle bar
 * - `foo` _{Array}_ foos to use (optional)
 *
 * @param {Object} options
 * @return Something (constructed)
 * @api public
 */

function Something(opts) {
  if (!(this instanceof Something)) return new Something(opts);
  // ...
}
 
/**
 * #### .doSomething([param,] cb)
 *
 * This is will do something cool. Check out code sample 
 * of this doing something cool async.
 *
 * ```js
 * something.doSomething('universe', function (err, result) {
 *   // ...
 * });
 * ```
 * 
 * @param {String} param (optional)
 * @param {Function} callback
 * @cb {Error|null} if error
 * @cb {String} result of coolness
 * @name doSomething
 * @api public
 */

SomethingCool.prototype.doSomething = function(param, cb) {
  // ..
  if (cb) cb(null, 'cool!');
};
Private Example (not visible in docs)
/*!
 * This is will do something cool internally.
 *
 * Options
 * - `one` _{String}_ first option
 * - `two` _{String}_ second option
 * 
 * @param {Object} parameter we are doing something with
 * @ctx SomethingCool
 * @return {String} result of coolness
 * @api private
 */

function doSomething(opts} {
  var self = this; // which is a constructed SomethingCool
  return 'cool!';
}