IteratorZip.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. 'use strict';
  2. var $TypeError = require('es-errors/type');
  3. var CreateIteratorFromClosure = require('./CreateIteratorFromClosure');
  4. var IteratorCloseAll = require('./IteratorCloseAll');
  5. var IteratorStep = require('es-abstract/2024/IteratorStep');
  6. var IteratorStepValue = require('es-abstract/2024/IteratorStepValue');
  7. var NormalCompletion = require('es-abstract/2024/NormalCompletion');
  8. var ThrowCompletion = require('es-abstract/2024/ThrowCompletion');
  9. var isAbstractClosure = require('es-abstract/helpers/isAbstractClosure');
  10. var IsArray = require('es-abstract/helpers/IsArray');
  11. var isIteratorRecord = require('es-abstract/helpers/records/iterator-record');
  12. var every = require('es-abstract/helpers/every');
  13. var callBound = require('call-bound');
  14. var $indexOf = callBound('Array.prototype.indexOf');
  15. var $slice = callBound('Array.prototype.slice');
  16. var $splice = callBound('Array.prototype.splice');
  17. var iterHelperProto = require('../IteratorHelperPrototype');
  18. var SLOT = require('internal-slot');
  19. // https://tc39.es/proposal-joint-iteration/#sec-IteratorZip
  20. module.exports = function IteratorZip(iters, mode, padding, finishResults) {
  21. if (!IsArray(iters) || !every(iters, isIteratorRecord)) {
  22. throw new $TypeError('`iters` must be a List of IteratorRecords');
  23. }
  24. if (mode !== 'shortest' && mode !== 'longest' && mode !== 'strict') {
  25. throw new $TypeError('`mode` must be one of "shortest", "longest", or "strict"');
  26. }
  27. if (!IsArray(padding)) {
  28. throw new $TypeError('`padding` must be a List');
  29. }
  30. if (!isAbstractClosure(finishResults)) {
  31. throw new $TypeError('`finishResults` must be an Abstract Closure');
  32. }
  33. var iterCount = iters.length; // step 1
  34. var openIters = $slice(iters); // step 2
  35. var sentinel = {};
  36. var closure = function () {
  37. if (iterCount === 0) {
  38. // 1. If iterCount = 0, return ReturnCompletion(undefined).
  39. return sentinel; // step 1
  40. }
  41. // while (true) {
  42. { // eslint-disable-line no-lone-blocks
  43. var results = []; // step 3.b.i
  44. if (openIters.length === 0) {
  45. throw new $TypeError('Assertion failed: `openIters` is empty'); // step 3.b.ii
  46. }
  47. for (var i = 0; i < iterCount; ++i) { // step 3.b.iii
  48. // for (var i = 0; i < iterCount; i += 1) { // step 3.b.iii
  49. var result;
  50. var iter = iters[i];
  51. if (iter === null) { // step 3.b.iii.1
  52. if (mode !== 'longest') {
  53. throw new $TypeError('Assertion failed: `mode` is not "longest"'); // step 3.b.iii.1.a
  54. }
  55. result = padding[i]; // step 3.b.iii.1.b
  56. } else { // step 2
  57. try {
  58. result = IteratorStepValue(iter); // step 3.b.iii.2.a, 3.b.iii.2.c
  59. } catch (e) { // step 3.b.iii.2.b
  60. $splice(openIters, $indexOf(openIters, iter), 1); // step 3.b.iii.2.b.i
  61. return IteratorCloseAll(openIters, ThrowCompletion(e)); // step 3.b.iii.2.b.ii
  62. }
  63. if (iter['[[Done]]']) { // step 3.b.iii.2.d
  64. $splice(openIters, $indexOf(openIters, iter), 1); // step 3.b.iii.2.d.i
  65. if (mode === 'shortest') { // step 3.b.iii.2.d.ii
  66. IteratorCloseAll(openIters, NormalCompletion(undefined)); // step 3.b.iii.2.d.ii.i
  67. return sentinel;
  68. } else if (mode === 'strict') { // step 3.b.iii.2.d.iii
  69. if (i !== 0) { // step 3.b.iii.2.d.iii.i
  70. return IteratorCloseAll(
  71. openIters,
  72. ThrowCompletion(new $TypeError('Assertion failed: `i` is not 0'))
  73. ); // step 3.b.iii.2.d.iii.i.i
  74. }
  75. for (var k = 1; k < iterCount; k += 1) { // step 3.b.iii.2.d.iii.ii
  76. if (iters[k] === null) {
  77. throw new $TypeError('Assertion failed: `iters[k]` is `null`'); // step 3.b.iii.2.d.iii.ii.i
  78. }
  79. try {
  80. result = IteratorStep(iters[k]); // step 3.b.iii.2.d.iii.ii.ii, 3.b.iii.2.d.iii.ii.iii.ii.iv
  81. } catch (e) { // step 3.b.iii.2.d.iii.ii.iii
  82. return IteratorCloseAll(openIters, ThrowCompletion(e)); // step 3.b.iii.2.d.iii.ii.iii.ii
  83. }
  84. // if (open === false) { // step 3.b.iii.2.d.iii.ii.v
  85. if (iters[k]['[[Done]]']) { // step 3.b.iii.2.d.iii.ii.v
  86. $splice(openIters, $indexOf(openIters, iters[k]), 1); // step 3.b.iii.2.d.iii.ii.v.i
  87. } else { // step 3.b.iii.2.d.iii.ii.vi
  88. return IteratorCloseAll(
  89. openIters,
  90. ThrowCompletion(new $TypeError('Assertion failed: `open` is not `false`'))
  91. ); // step 3.b.iii.2.d.iii.ii.vi.i
  92. }
  93. }
  94. } else { // step 3.b.iii.2.d.iv
  95. if (mode !== 'longest') {
  96. throw new $TypeError('Assertion failed: `mode` is not "longest"'); // step 3.b.iii.2.d.iv.i
  97. }
  98. if (openIters.length === 0) {
  99. return sentinel; // ReturnCompletion(undefined); // step 3.b.iii.2.d.iv.ii
  100. }
  101. // eslint-disable-next-line no-param-reassign
  102. iters[i] = null; // step 3.b.iii.2.d.iv.iii
  103. // i += 1;
  104. result = padding[i]; // step 3.b.iii.2.d.iv.iv
  105. }
  106. }
  107. }
  108. results[results.length] = result; // step 3.b.iii.3
  109. // 5. Let completion be Completion(Yield(results)).
  110. // 6. If completion is an abrupt completion, then
  111. // 1. Return ? IteratorCloseAll(openIters, completion).
  112. }
  113. }
  114. return finishResults(results); // step 3.b.iv
  115. };
  116. SLOT.set(closure, '[[Sentinel]]', sentinel); // for the userland implementation
  117. SLOT.set(closure, '[[CloseIfAbrupt]]', finishResults); // for the userland implementation
  118. var gen = CreateIteratorFromClosure(closure, 'Iterator Helper', iterHelperProto, ['[[UnderlyingIterators]]']); // step 4
  119. SLOT.set(gen, '[[UnderlyingIterators]]', openIters); // step 5
  120. return gen; // step 6
  121. };