code: function defineOperation(fn, paramDefs) {
    return function() {
      const args = Array.prototype.slice.call(arguments);
      const params = [];
      for (let i = 0, argIdx = 0; i < paramDefs.length; ++i, ++argIdx) {
        const def = paramDefs[i];
        let arg = args[argIdx];
  
        if (def.hasOwnProperty('default') && arg == null) arg = def.default;
        if (def.type === 'object' && def.default != null) {
          arg = Object.assign({}, def.default, arg);
        }
  
        // special case to allow `options` to be optional
        if (def.name === 'options' && (typeof arg === 'function' || arg == null)) {
          arg = {};
        }
  
        if (validateParameter(arg, paramDefs, i)) {
          params.push(arg);
        } else {
          argIdx--;
        }
      }
  
      const callback = arguments[arguments.length - 1];
      if (typeof callback !== 'function') {
        return new Promise((resolve, reject) => {
          params.push((err, response) => {
            if (err) return reject(err);
            resolve(response);
          });
  
          fn.apply(this, params);
        });
      }
  
      fn.apply(this, params);
    };
  }
docs: Monkey-patches an existing method to support parameter validation, as well
  as adding support for returning Promises if callbacks are not provided.
  
  @private
  @param {function} fn the function to override
  @param {Array<Object>} paramDefs the definitions of each parameter to the function