index.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. 'use strict';
  2. var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
  3. function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
  4. // Import
  5. var typeChecker = require('typechecker');
  6. // Define
  7. module.exports = function ambi(method) {
  8. for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  9. args[_key - 1] = arguments[_key];
  10. }
  11. // Prepare
  12. var fireMethod = void 0,
  13. introspectMethod = void 0;
  14. // If binding has occured then make sure we are introspecting the write method
  15. // by allowing the user to pass method as an array of two methods
  16. // the method to fire, and the method to introspect
  17. if (typeChecker.isArray(method)) {
  18. var _method = _slicedToArray(method, 2);
  19. fireMethod = _method[0];
  20. introspectMethod = _method[1];
  21. } else {
  22. fireMethod = introspectMethod = method;
  23. }
  24. // Extract the preceeding arguments and the completion callback
  25. var simpleArguments = args.slice(0, -1);
  26. var completionCallback = args.slice(-1)[0];
  27. // Check the completion callback is actually a function
  28. if (!typeChecker.isFunction(completionCallback)) {
  29. throw new Error('ambi was called without a completion callback');
  30. }
  31. /*
  32. Different ways functions can be called:
  33. ambi(function(a,next){return next()}, a, next)
  34. > VALID: execute asynchronously
  35. > given arguments are SAME as the accepted arguments
  36. > method will be fired with (a, next)
  37. ambi(function(a,next){return next()}, next)
  38. > VALID: execute asynchronously
  39. > given arguments are LESS than the accepted arguments
  40. > method will be fired with (undefined, next)
  41. ambi(function(a){}, a, next)
  42. > VALID: execute synchronously
  43. > given arguments are MORE than expected arguments
  44. > method will be fired with (a)
  45. ambi(function(a){}, next)
  46. > INVALID: execute asynchronously
  47. > given arguments are SAME as the accepted arguments
  48. > method will be fired with (next)
  49. > if they want to use optional args, the function must accept a completion callback
  50. */
  51. var givenArgumentsLength = args.length;
  52. var acceptedArgumentsLength = introspectMethod.length;
  53. var argumentsDifferenceLength = null;
  54. var executeAsynchronously = null;
  55. // Given arguments are SAME as the expected arguments
  56. // This will execute asynchronously
  57. // Don't have to do anything with the arguments
  58. if (givenArgumentsLength === acceptedArgumentsLength) {
  59. executeAsynchronously = true;
  60. }
  61. // Given arguments are LESS than the expected arguments
  62. // This will execute asynchronously
  63. // We will need to supplement any missing expected arguments with undefined
  64. // to ensure the compeltion callback is in the right place in the arguments listing
  65. else if (givenArgumentsLength < acceptedArgumentsLength) {
  66. executeAsynchronously = true;
  67. argumentsDifferenceLength = acceptedArgumentsLength - givenArgumentsLength;
  68. args = simpleArguments.slice().concat(new Array(argumentsDifferenceLength)).concat([completionCallback]);
  69. }
  70. // Given arguments are MORE than the expected arguments
  71. // This will execute synchronously
  72. // We should to trim off the completion callback from the arguments
  73. // as the synchronous function won't care for it
  74. // while this isn't essential
  75. // it will provide some expectation for the user as to which mode their function was executed in
  76. else {
  77. executeAsynchronously = false;
  78. args = simpleArguments.slice();
  79. }
  80. // Execute with the exceptation that the method will fire the completion callback itself
  81. if (executeAsynchronously) {
  82. // Fire the method
  83. fireMethod.apply(undefined, _toConsumableArray(args));
  84. }
  85. // Execute with the expectation that we will need to fire the completion callback ourselves
  86. // Always call the completion callback ourselves as the fire method does not make use of it
  87. else {
  88. // Fire the method and check for returned errors
  89. var result = fireMethod.apply(undefined, _toConsumableArray(args));
  90. // Check the result for a returned error
  91. if (typeChecker.isError(result)) {
  92. // An error was returned so fire the completion callback with the error
  93. var err = result;
  94. completionCallback(err);
  95. } else {
  96. // Everything worked, so fire the completion callback without an error and with the result
  97. completionCallback(null, result);
  98. }
  99. }
  100. // Return nothing as we expect ambi to deal with synchronous and asynchronous methods
  101. // so returning something will only work for synchronous methods
  102. // and not asynchronous ones
  103. // so returning anything would be inconsistent
  104. return null;
  105. };