This repository has been archived by the owner on Sep 17, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
value-it.ts
90 lines (76 loc) · 2.96 KB
/
value-it.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { isPushIterable, makePushIterable, makePushIterator } from '../base';
import { iterable$process } from '../base/iterable.impl';
import { PushIterator$empty } from '../base/push-iterator.empty.impl';
import type { PushIterable } from '../push-iterable';
import { PushIterator__symbol } from '../push-iterable';
import { PushIterationMode } from '../push-iteration-mode';
import type { PushIterator } from '../push-iterator';
/**
* Creates a {@link PushIterable | push iterable} with the values of elements of the `source` iterable.
*
* Element value is the result of provided function call, except `false`, `null`, and `undefined` which are filtered
* out.
*
* This can be used as a more effective {@link mapIt} / {@link filterIt} combination.
*
* @typeParam T - A type of source elements.
* @typeParam TValue - A type of source element values.
* @param source - A source iterable.
* @param valueOf - A function that values elements, taking the source element as the only parameter, and returning
* either its value, or `false`/`null`/`undefined` to filter it out.
*
* @returns New push iterable with the element values.
*/
export function valueIt<T, TValue = T>(
source: Iterable<T>,
valueOf: (this: void, element: T) => TValue | false | null | undefined,
): PushIterable<TValue> {
return makePushIterable((accept, mode = PushIterationMode.Some): PushIterator<TValue> => {
if (accept && mode > 0) {
const acceptElement = (element: T): boolean | void => {
const value = valueOf(element);
return value != null && value !== false ? accept(value) : void 0;
};
return isPushIterable(source)
? (source[PushIterator__symbol](acceptElement, mode) as PushIterator<never>) // Iteration over.
: iterable$process<T, TValue>(source, acceptElement, mode);
}
const forNext = isPushIterable(source)
? valueIt$(source, valueOf)
: valueIt$raw(source, valueOf);
return accept && !forNext(accept) ? PushIterator$empty : makePushIterator(forNext);
});
}
function valueIt$<T, TValue>(
source: PushIterable<T>,
valueOf: (this: void, element: T) => TValue | false | null | undefined,
): PushIterator.Pusher<TValue> {
return accept => !(source = source[PushIterator__symbol](element => {
const value = valueOf(element);
return value != null && value !== false ? accept(value) : void 0;
})).isOver();
}
function valueIt$raw<T, TValue>(
source: Iterable<T>,
valueOf: (this: void, element: T) => TValue | false | null | undefined,
): PushIterator.Pusher<TValue> {
const it = source[Symbol.iterator]();
if (isPushIterable(it)) {
return valueIt$(it, valueOf);
}
return accept => {
for (;;) {
const next = it.next();
if (next.done) {
return false;
}
const value = valueOf(next.value);
if (value != null && value !== false) {
const status = accept(value);
if (typeof status === 'boolean') {
return status;
}
}
}
};
}