filter.js

import {asAsyncIterator, syncType} from './lib/get_iterator'
import {asyncFilterWhen, syncFilterWhen} from './filter_when'

/**
```
import {filter} from 'async_iter/pipeline/filter' # pipeline version
import {filter} from 'async_iter/filter' # conventional version
```
Filters out items from the source iteration, based on the supplied test function
> Supports both **sync** and **async** iterations

 * @param  {Iterable}         source          The source iteration to filter
 * @param  {Function}         fn              A funntion invokved for each item, returning false for items to be removed
 * @param  {missingValueFn=}  missingValueFn  When supplied, will be invokved for each group of items that are filter - returns a item to be emitted, representing the filtered items
 * @return {Iterable} The filtered items
 * @function
 * @name filter
 * @memberof module:Operators
@description
The optional `missingValueFn` allows for processing the 'filtered' items into a single item.

eg: Given an input source of [1, 2, 3, 4, 5, 6] and a filter of x >= 5, then the missingValueFn will be called with
values of (1, 5) and the result of that function will be emitted before item 6.

The examples include use of the `missingValueFn` function
 */

export const filter = syncType(syncFilter, asyncFilter)

function* syncFilter(source, fn, missingValueFn = undefined) {
  if (missingValueFn !== undefined)
    return yield* syncFilterWhen(source, fn, missingValueFn)

  for (const x of source)
    if (fn(x))
      yield x
}

async function* asyncFilter(source, fn, missingValueFn = undefined) {
  if (missingValueFn !== undefined)
    return yield* asyncFilterWhen(source, fn, missingValueFn)

  source = await asAsyncIterator(source)

  for await (const x of source)
    if (await fn(x))
      yield x
}