extra-iterator 0.11.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +54 -5
- package/dist/index.js +77 -16
- package/dist/index.test.js +11 -2
- package/package.json +4 -2
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,33 @@ interface ArrayIsh<T> {
|
|
|
3
3
|
length: number;
|
|
4
4
|
}
|
|
5
5
|
export type ExtraIteratorSource<T> = Iterator<T, any, any> | Iterable<T, any, any> | ArrayIsh<T>;
|
|
6
|
+
/**
|
|
7
|
+
* An extended iterator class that provides additional chainable utility methods for working with iterables.
|
|
8
|
+
*
|
|
9
|
+
* @template T The type of values yielded by this iterator.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Creating an iterator from an array
|
|
13
|
+
* const iter = ExtraIterator.from([1, 2, 3, 4, 5]);
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Creating a sequence of ancestors of a given element
|
|
17
|
+
* ExtraIterator.from(function*() {
|
|
18
|
+
*
|
|
19
|
+
* }()).toArray();
|
|
20
|
+
* ExtraIterator.from([1, 2, 3, 4, 5])
|
|
21
|
+
* .filter(n => n % 2 === 0)
|
|
22
|
+
* .map(n => n * 2)
|
|
23
|
+
* .toArray()
|
|
24
|
+
* // returns [4, 8]
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // Using static factory methods
|
|
28
|
+
* ExtraIterator.range(1, 5)
|
|
29
|
+
* .map(n => n * n)
|
|
30
|
+
* .toArray()
|
|
31
|
+
* // returns [1, 4, 9, 16]
|
|
32
|
+
*/
|
|
6
33
|
export declare class ExtraIterator<T> extends Iterator<T, any, any> {
|
|
7
34
|
static from<T>(source: ExtraIteratorSource<T>): ExtraIterator<T>;
|
|
8
35
|
static zip<A, B>(a: ExtraIteratorSource<A>, b: ExtraIteratorSource<B>): ExtraIterator<[A, B]>;
|
|
@@ -25,6 +52,12 @@ export declare class ExtraIterator<T> extends Iterator<T, any, any> {
|
|
|
25
52
|
* @example ExtraIterator.empty().toArray() // returns []
|
|
26
53
|
*/
|
|
27
54
|
static empty<T = any>(): ExtraIterator<T>;
|
|
55
|
+
/**
|
|
56
|
+
* Creates an iterator that yields a single value.
|
|
57
|
+
*
|
|
58
|
+
* @example ExtraIterator.single(42).toArray() // returns [42]
|
|
59
|
+
*/
|
|
60
|
+
static single<T>(value: T): ExtraIterator<T>;
|
|
28
61
|
/**
|
|
29
62
|
* Creates an iterator that yields incrementing numbers.
|
|
30
63
|
*
|
|
@@ -70,14 +103,30 @@ export declare class ExtraIterator<T> extends Iterator<T, any, any> {
|
|
|
70
103
|
*/
|
|
71
104
|
static repeat<T>(value: T): ExtraIterator<T>;
|
|
72
105
|
/**
|
|
73
|
-
* Generates an infinite sequence of
|
|
74
|
-
*
|
|
106
|
+
* Generates an infinite sequence of random numbers between 0 and 1 (exclusive) using `Math.random` or another
|
|
107
|
+
* specified random number generator.
|
|
75
108
|
*
|
|
76
109
|
* > ⚠ This iterator is infinite. Use {@link take} method if you want a specific number of values.
|
|
77
110
|
*/
|
|
78
|
-
static random(
|
|
79
|
-
|
|
80
|
-
|
|
111
|
+
static random(rng?: () => number): ExtraIterator<number>;
|
|
112
|
+
/**
|
|
113
|
+
* Generates an infinite sequence of cryptographically strong random bytes using `crypto.getRandomValues`, in
|
|
114
|
+
* chunks of `chunkSize` bytes.
|
|
115
|
+
*
|
|
116
|
+
* By default, this method reuses the same `ArrayBuffer` instance for each chunk, refilling it with new random
|
|
117
|
+
* values at each iteration, so you should not keep references to the yielded buffers. Set `reuseBuffer` to `false`
|
|
118
|
+
* if you want this method to yield copies of the buffer instead.
|
|
119
|
+
*
|
|
120
|
+
* If you want a flat sequence of individual byte values instead of chunks, you can chain the iterator returned by
|
|
121
|
+
* this method with the {@link flatten} method. The resulting iterator will contain interger values from 0 to 255
|
|
122
|
+
* (inclusive).
|
|
123
|
+
*
|
|
124
|
+
* > ⚠ This iterator is infinite. Use {@link take} method if you want a specific number of values.
|
|
125
|
+
*/
|
|
126
|
+
static randomBytes({ chunkSize, reuseBuffer }?: {
|
|
127
|
+
chunkSize?: number | undefined;
|
|
128
|
+
reuseBuffer?: boolean | undefined;
|
|
129
|
+
}): ExtraIterator<ArrayBuffer>;
|
|
81
130
|
private constructor();
|
|
82
131
|
private source;
|
|
83
132
|
next(value?: any): IteratorResult<T, any>;
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An extended iterator class that provides additional chainable utility methods for working with iterables.
|
|
3
|
+
*
|
|
4
|
+
* @template T The type of values yielded by this iterator.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* // Creating an iterator from an array
|
|
8
|
+
* const iter = ExtraIterator.from([1, 2, 3, 4, 5]);
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // Creating a sequence of ancestors of a given element
|
|
12
|
+
* ExtraIterator.from(function*() {
|
|
13
|
+
*
|
|
14
|
+
* }()).toArray();
|
|
15
|
+
* ExtraIterator.from([1, 2, 3, 4, 5])
|
|
16
|
+
* .filter(n => n % 2 === 0)
|
|
17
|
+
* .map(n => n * 2)
|
|
18
|
+
* .toArray()
|
|
19
|
+
* // returns [4, 8]
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Using static factory methods
|
|
23
|
+
* ExtraIterator.range(1, 5)
|
|
24
|
+
* .map(n => n * n)
|
|
25
|
+
* .toArray()
|
|
26
|
+
* // returns [1, 4, 9, 16]
|
|
27
|
+
*/
|
|
1
28
|
export class ExtraIterator extends Iterator {
|
|
2
29
|
// =================================================================================================================
|
|
3
30
|
// STATIC FUNCTIONS
|
|
4
31
|
// =================================================================================================================
|
|
5
|
-
// TODO Consider using a lib like `make-iterator` to transform things into iterators
|
|
6
32
|
static from(source) {
|
|
7
33
|
if (!(Symbol.iterator in source) && 'length' in source) {
|
|
8
34
|
return new ExtraIterator(function* () {
|
|
@@ -29,6 +55,14 @@ export class ExtraIterator extends Iterator {
|
|
|
29
55
|
static empty() {
|
|
30
56
|
return new ExtraIterator([]);
|
|
31
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Creates an iterator that yields a single value.
|
|
60
|
+
*
|
|
61
|
+
* @example ExtraIterator.single(42).toArray() // returns [42]
|
|
62
|
+
*/
|
|
63
|
+
static single(value) {
|
|
64
|
+
return new ExtraIterator([value]);
|
|
65
|
+
}
|
|
32
66
|
/**
|
|
33
67
|
* Creates an iterator that yields incrementing numbers.
|
|
34
68
|
*
|
|
@@ -98,16 +132,37 @@ export class ExtraIterator extends Iterator {
|
|
|
98
132
|
}());
|
|
99
133
|
}
|
|
100
134
|
/**
|
|
101
|
-
* Generates an infinite sequence of
|
|
102
|
-
*
|
|
135
|
+
* Generates an infinite sequence of random numbers between 0 and 1 (exclusive) using `Math.random` or another
|
|
136
|
+
* specified random number generator.
|
|
103
137
|
*
|
|
104
138
|
* > ⚠ This iterator is infinite. Use {@link take} method if you want a specific number of values.
|
|
105
139
|
*/
|
|
106
|
-
static random(
|
|
107
|
-
|
|
140
|
+
static random(rng = Math.random) {
|
|
141
|
+
return ExtraIterator.from(function* () {
|
|
142
|
+
while (true) {
|
|
143
|
+
yield rng();
|
|
144
|
+
}
|
|
145
|
+
}());
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Generates an infinite sequence of cryptographically strong random bytes using `crypto.getRandomValues`, in
|
|
149
|
+
* chunks of `chunkSize` bytes.
|
|
150
|
+
*
|
|
151
|
+
* By default, this method reuses the same `ArrayBuffer` instance for each chunk, refilling it with new random
|
|
152
|
+
* values at each iteration, so you should not keep references to the yielded buffers. Set `reuseBuffer` to `false`
|
|
153
|
+
* if you want this method to yield copies of the buffer instead.
|
|
154
|
+
*
|
|
155
|
+
* If you want a flat sequence of individual byte values instead of chunks, you can chain the iterator returned by
|
|
156
|
+
* this method with the {@link flatten} method. The resulting iterator will contain interger values from 0 to 255
|
|
157
|
+
* (inclusive).
|
|
158
|
+
*
|
|
159
|
+
* > ⚠ This iterator is infinite. Use {@link take} method if you want a specific number of values.
|
|
160
|
+
*/
|
|
161
|
+
static randomBytes({ chunkSize = 1024, reuseBuffer = true } = {}) {
|
|
162
|
+
const bytes = new Uint8Array(chunkSize);
|
|
108
163
|
return new ExtraIterator(function* () {
|
|
109
|
-
globalThis.crypto.getRandomValues(
|
|
110
|
-
yield
|
|
164
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
165
|
+
yield reuseBuffer ? bytes.buffer : new Uint8Array(bytes).buffer;
|
|
111
166
|
}())
|
|
112
167
|
.loop();
|
|
113
168
|
}
|
|
@@ -140,17 +195,19 @@ export class ExtraIterator extends Iterator {
|
|
|
140
195
|
take(limit) {
|
|
141
196
|
return limit >= 0
|
|
142
197
|
? ExtraIterator.from(super.take(limit))
|
|
143
|
-
:
|
|
198
|
+
: this.takeLast(-limit);
|
|
144
199
|
}
|
|
145
200
|
takeLast(count) {
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
result.shift();
|
|
151
|
-
}
|
|
201
|
+
const ringbuffer = new Array(count);
|
|
202
|
+
let index = 0;
|
|
203
|
+
for (let item; item = this.next(), !item.done; index = (index + 1) % count) {
|
|
204
|
+
ringbuffer[index] = item.value;
|
|
152
205
|
}
|
|
153
|
-
return
|
|
206
|
+
return ExtraIterator.from(function* () {
|
|
207
|
+
for (let i = index; i < count + index; i++) {
|
|
208
|
+
yield ringbuffer[i % count];
|
|
209
|
+
}
|
|
210
|
+
}());
|
|
154
211
|
}
|
|
155
212
|
drop(count) {
|
|
156
213
|
return count >= 0
|
|
@@ -174,7 +231,11 @@ export class ExtraIterator extends Iterator {
|
|
|
174
231
|
* @example ExtraIterator.from([[1, 2], [3, 4]]).flatten().toArray() // returns [1, 2, 3, 4]
|
|
175
232
|
*/
|
|
176
233
|
flatten() {
|
|
177
|
-
return this.flatMap(value =>
|
|
234
|
+
return this.flatMap(value => typeof value === 'object'
|
|
235
|
+
&& value !== null
|
|
236
|
+
&& Symbol.iterator in value
|
|
237
|
+
? new ExtraIterator(value).flatten()
|
|
238
|
+
: [value]);
|
|
178
239
|
}
|
|
179
240
|
/**
|
|
180
241
|
* Creates a new iterator that yields the values of this iterator, but won't yield any duplicates.
|
package/dist/index.test.js
CHANGED
|
@@ -37,10 +37,15 @@ describe(ExtraIterator.name, () => {
|
|
|
37
37
|
const iterator = ExtraIterator.repeat('x').take(3);
|
|
38
38
|
expect(iterator.toArray()).toEqual(['x', 'x', 'x']);
|
|
39
39
|
});
|
|
40
|
-
it('should yield random
|
|
40
|
+
it('should yield random numbers', () => {
|
|
41
41
|
const values = ExtraIterator.random().take(10000).toArray();
|
|
42
42
|
expect(values.length).toBe(10000);
|
|
43
|
-
expect(values.every(value => typeof value === 'number' && value >= 0 && value <
|
|
43
|
+
expect(values.every(value => typeof value === 'number' && value >= 0 && value < 1)).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
it('should yield random bytes', () => {
|
|
46
|
+
const values = ExtraIterator.randomBytes({ chunkSize: 1024 }).take(1).map(chunk => new Uint8Array(chunk)).flatten().toArray();
|
|
47
|
+
expect(values.length).toBe(1024);
|
|
48
|
+
expect(values.every(value => typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 255)).toBe(true);
|
|
44
49
|
});
|
|
45
50
|
it('should filter values based on a predicate', () => {
|
|
46
51
|
const iterator = ExtraIterator.from([1, 2, 3, 4]).filter(x => x % 2 === 0);
|
|
@@ -70,6 +75,10 @@ describe(ExtraIterator.name, () => {
|
|
|
70
75
|
const iterator = ExtraIterator.from([1, 2, 3]);
|
|
71
76
|
expect(iterator.first()).toBe(1);
|
|
72
77
|
});
|
|
78
|
+
it('should have a single value', () => {
|
|
79
|
+
const iterator = ExtraIterator.single(42);
|
|
80
|
+
expect(iterator.first()).toBe(42);
|
|
81
|
+
});
|
|
73
82
|
describe(ExtraIterator.prototype.last.name, () => {
|
|
74
83
|
it('should return the last value if the iterator is not empty', () => {
|
|
75
84
|
const iterator = ExtraIterator.from([1, 2, 3]);
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "An extension of the Iterator class with additional utility helper functions.",
|
|
4
4
|
"author": "Leonardo Raele <leonardoraele@gmail.com>",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.13.0",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": "./dist/index.js",
|
|
@@ -13,9 +13,11 @@
|
|
|
13
13
|
"dist"
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
|
-
"test": "run-
|
|
16
|
+
"test": "run-p test:*",
|
|
17
17
|
"test:types": "tsc --noEmit",
|
|
18
18
|
"test:unit": "node --import=tsx --test **/*.test.ts",
|
|
19
|
+
"coverage": "run-s build coverage:test",
|
|
20
|
+
"coverage:test": "node --import=tsx --test --experimental-test-coverage",
|
|
19
21
|
"build": "tsc",
|
|
20
22
|
"prebuild": "rimraf dist",
|
|
21
23
|
"prepack": "run-s test build"
|