gen.js 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. 'use strict';
  2. const defs = require('./defs');
  3. const next = async function* (value, fns, index) {
  4. for (let i = index; i <= fns.length; ++i) {
  5. if (value && typeof value.then == 'function') {
  6. // thenable
  7. value = await value;
  8. }
  9. if (value === defs.none) break;
  10. if (value === defs.stop) throw new defs.Stop();
  11. if (value && value[defs.finalSymbol] === 1) {
  12. yield value.value;
  13. break;
  14. }
  15. if (value && value[defs.manySymbol] === 1) {
  16. const values = value.values;
  17. if (i == fns.length) {
  18. yield* values;
  19. } else {
  20. for (let j = 0; j < values.length; ++j) {
  21. yield* next(values[j], fns, i);
  22. }
  23. }
  24. break;
  25. }
  26. if (value && typeof value.next == 'function') {
  27. // generator
  28. for (;;) {
  29. let data = value.next();
  30. if (data && typeof data.then == 'function') {
  31. data = await data;
  32. }
  33. if (data.done) break;
  34. if (i == fns.length) {
  35. yield data.value;
  36. } else {
  37. yield* next(data.value, fns, i);
  38. }
  39. }
  40. break;
  41. }
  42. if (i == fns.length) {
  43. yield value;
  44. break;
  45. }
  46. const f = fns[i];
  47. value = f(value);
  48. }
  49. };
  50. const gen = (...fns) => {
  51. fns = fns.filter(fn => fn);
  52. if (fns.length) {
  53. if (Symbol.asyncIterator && fns[0][Symbol.asyncIterator]) {
  54. fns[0] = fns[0][Symbol.asyncIterator].bind(fns[0]);
  55. } else if (Symbol.iterator && fns[0][Symbol.iterator]) {
  56. fns[0] = fns[0][Symbol.iterator].bind(fns[0]);
  57. }
  58. } else {
  59. fns = [x => x];
  60. }
  61. let flushed = false;
  62. const g = async function* (value) {
  63. if (flushed) throw Error('Call to a flushed pipe.');
  64. if (value !== defs.none) {
  65. yield* next(value, fns, 0);
  66. } else {
  67. flushed = true;
  68. for (let i = 0; i < fns.length; ++i) {
  69. const f = fns[i];
  70. if (f[defs.flushSymbol] === 1) {
  71. yield* next(f(defs.none), fns, i + 1);
  72. }
  73. }
  74. }
  75. };
  76. const needToFlush = fns.some(fn => fn[defs.flushSymbol] === 1);
  77. return needToFlush ? defs.flushable(g) : g;
  78. };
  79. gen.next = next;
  80. Object.assign(gen, defs);
  81. module.exports = gen;