code: function hook(options) {
    let preHooks = options.preHooks;
    if (Array.isArray(preHooks) === false) {
      preHooks = [];
    }
  
    let postHooks = options.postHooks;
    if (Array.isArray(postHooks) === false) {
      postHooks = [];
    }
  
    let doc = options.doc; // We need the doc to set the context of the hooks
    let async = options.async || false;
    let fn = options.fn; // The function that we are hook
    let fnArgs = options.fnArgs;
  
    if (async === true) {
      return new Promise(function(resolve, reject) {
        _asyncHook({
          resolve: resolve,
          reject: reject,
          preHooks: preHooks,
          postHooks: postHooks,
          doc: doc,
          fn: fn,
          fnArgs: fnArgs
        });
      });
    }
  
    return _syncHook({
      preHooks: preHooks,
      postHooks: postHooks,
      doc: doc,
      fn: fn,
      fnArgs: fnArgs
    });
  }
docs: Return a promise if a hook is asynchronous
  Note: If no hook is asynchronous, `fn` can still be asynchronous in which
  case we return a promise or undefined
  @param {Object} options, the arguments are:
  - preHooks {Array} the methods to execute before the main one
  - postHooks {Array} the methods to execute after the main one
  - async {boolean} whether this this hook is asynchronous or not
  - doc {Document} the document that triggered the hooks
  - fn {Function} the main function
  - fnArgs {Array} arguments for `fn`
  @return {Promise=}