lib/utils/iterator.js

/**
 * @module lib/utils/iterator
 */

/**
 * Transforms an iterable of iterables into a flat iterable
 */
export function flatten(iterable, accessIterable) {
  const iterator = iterable[Symbol.iterator]();
  let oldNext = iterator.next.bind(iterator);
  let c;
  let subIterator;
  let subc = {done: true};
  iterator.next = () => {
    while(subc.done) {
      c = oldNext();
      if(c.done) {
        return c;
      }
      subIterator = accessIterable(c.value)[Symbol.iterator];
      subc = subIterator.next();
    }
    return subc;
  };
  iterator[Symbol.iterator] = () => iterator;
  return iterator; 
};

/**
 * Creates an empty iterator
 */
export function empty() {
  const iterator = {
    next: () => ({done: true})
  };
  iterator[Symbol.iterator] = () => iterator;
  return iterator;
};

/**
 * Wraps a variable in an iterator
 */
export function wrap(value) {
  let seen = false;
  const iterator = {
    next: () => {
      if(seen) {
        return {done: true};
      } 
      seen = true;
      return {value};
    }
  };
  iterator[Symbol.iterator] = () => iterator;
  return iterator;
};

/**
 * Apply a function on a value when accessing it
 */
export function hijack(iterable, callback) {
  const iterator = iterable[Symbol.iterator]();
  const oldNext = iterator.next.bind(iterator);
  iterator.next = () => {
    const c = oldNext();
    if(!c.done) {
      c.value = callback(c.value);
    }
    return n;
  };
  iterator[Symbol.iterator] = () => iterator;
  return newIterator;
};