index.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. const npm = {
  2. stat: require('./static')
  3. };
  4. module.exports = function ($p) {
  5. const exp = {
  6. formatError: npm.stat.formatError,
  7. isPromise: npm.stat.isPromise,
  8. isReadableStream: npm.stat.isReadableStream,
  9. messageGap: npm.stat.messageGap,
  10. extend: npm.stat.extend,
  11. resolve: resolve,
  12. wrap: wrap
  13. };
  14. return exp;
  15. //////////////////////////////////////////
  16. // Checks if the function is a generator,
  17. // and if so - wraps it up into a promise;
  18. function wrap(func) {
  19. if (typeof func === 'function') {
  20. if (func.constructor.name === 'GeneratorFunction') {
  21. return asyncAdapter(func);
  22. }
  23. return func;
  24. }
  25. return null;
  26. }
  27. /////////////////////////////////////////////////////
  28. // Resolves a mixed value into the actual value,
  29. // consistent with the way mixed values are defined:
  30. // https://github.com/vitaly-t/spex/wiki/Mixed-Values
  31. function resolve(value, params, onSuccess, onError) {
  32. const self = this;
  33. let delayed = false;
  34. function loop() {
  35. while (typeof value === 'function') {
  36. if (value.constructor.name === 'GeneratorFunction') {
  37. value = asyncAdapter(value);
  38. }
  39. try {
  40. value = params ? value.apply(self, params) : value.call(self);
  41. } catch (e) {
  42. onError(e, false); // false means 'threw an error'
  43. return;
  44. }
  45. }
  46. if (exp.isPromise(value)) {
  47. value
  48. .then(data => {
  49. delayed = true;
  50. value = data;
  51. loop();
  52. return null; // this dummy return is just to prevent Bluebird warnings;
  53. })
  54. .catch(error => {
  55. onError(error, true); // true means 'rejected'
  56. });
  57. } else {
  58. onSuccess(value, delayed);
  59. }
  60. }
  61. loop();
  62. }
  63. // Generator-to-Promise adapter;
  64. // Based on: https://www.promisejs.org/generators/#both
  65. function asyncAdapter(generator) {
  66. return function () {
  67. const g = generator.apply(this, arguments);
  68. function handle(result) {
  69. if (result.done) {
  70. return $p.resolve(result.value);
  71. }
  72. return $p.resolve(result.value)
  73. .then(res => handle(g.next(res)), err => handle(g.throw(err)));
  74. }
  75. return handle(g.next());
  76. };
  77. }
  78. };