'use strict';

const Promise = require('bluebird');
const abbrev = require('abbrev');

class Console {
  constructor() {
    this.store = {};
    this.alias = {};
  }

  get(name) {
    name = name.toLowerCase();
    return this.store[this.alias[name]];
  }

  list() {
    return this.store;
  }

  register(name, desc, options, fn) {
    if (!name) throw new TypeError('name is required');

    if (!fn) {
      if (options) {
        if (typeof options === 'function') {
          fn = options;

          if (typeof desc === 'object') { // name, options, fn
            options = desc;
            desc = '';
          } else { // name, desc, fn
            options = {};
          }
        } else {
          throw new TypeError('fn must be a function');
        }
      } else {
        // name, fn
        if (typeof desc === 'function') {
          fn = desc;
          options = {};
          desc = '';
        } else {
          throw new TypeError('fn must be a function');
        }
      }
    }

    if (fn.length > 1) {
      fn = Promise.promisify(fn);
    } else {
      fn = Promise.method(fn);
    }

    const c = fn;
    this.store[name.toLowerCase()] = c;
    c.options = options;
    c.desc = desc;

    this.alias = abbrev(Object.keys(this.store));
  }
}

module.exports = Console;

@@ -84,218 +84,1070 @@
 );%0A%0A
-class Console %7B%0A  constructor() %7B%0A    this.store = %7B%7D;%0A    this.alias = %7B%7D;%0A  %7D%0A%0A  get(name) %7B%0A    name = name.toLowerCase();%0A    return this.store%5Bthis.alias%5Bname%5D%5D;%0A  %7D%0A%0A  list() %7B%0A    return this.store;%0A  %7D%0A
+/**%0A * Console plugin option%0A * @typedef %7BObject%7D Option%0A * @property %7BString%7D usage - The usage of a console command%0A * @property %7B%7Bname: String, desc: String%7D%5B%5D%7D arguments - The description of each argument of a console command%0A * @property %7B%7Bname: String, desc: String%7D%5B%5D%7D options - The description of each option of a console command%0A */%0A%0Aclass Console %7B%0A  constructor() %7B%0A    this.store = %7B%7D;%0A    this.alias = %7B%7D;%0A  %7D%0A%0A  /**%0A   * Get a console plugin function by name%0A   * @param %7BString%7D name - The name of the console plugin%0A   * @returns %7BFunction%7D - The console plugin function%0A   */%0A  get(name) %7B%0A    name = name.toLowerCase();%0A    return this.store%5Bthis.alias%5Bname%5D%5D;%0A  %7D%0A%0A  list() %7B%0A    return this.store;%0A  %7D%0A%0A  /**%0A   * Register a console plugin%0A   * @param %7BString%7D name - The name of console plugin to be registered%0A   * @param %7BString%7D desc - More detailed information about a console command%0A   * @param %7BOption%7D options - The description of each option of a console command%0A   * @param %7BFunction%7D fn - The console plugin to be registered%0A   */
 %0A  r

add jsdoc (#4500)