extra-iterator 0.5.0 → 0.7.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 CHANGED
@@ -13,8 +13,8 @@ export declare class ExtraIterator<T> extends Iterator<T, any, any> {
13
13
  static zip<A, B, C, D, E, F, G>(a: ExtraIteratorSource<A>, b: ExtraIteratorSource<B>, c: ExtraIteratorSource<C>, d: ExtraIteratorSource<D>, e: ExtraIteratorSource<E>, f: ExtraIteratorSource<F>, g: ExtraIteratorSource<G>): ExtraIterator<[A, B, C, D, E, F, G]>;
14
14
  static zip<A, B, C, D, E, F, G, H>(a: ExtraIteratorSource<A>, b: ExtraIteratorSource<B>, c: ExtraIteratorSource<C>, d: ExtraIteratorSource<D>, e: ExtraIteratorSource<E>, f: ExtraIteratorSource<F>, g: ExtraIteratorSource<G>, h: ExtraIteratorSource<H>): ExtraIterator<[A, B, C, D, E, F, G, H]>;
15
15
  /**
16
- * Creates an iterator that yields arrays containing the values that exist in the same indexes in each of the
17
- * provided iterators.
16
+ * Creates a new iterator that iterates over all the provided iterators simultaneously. The returned iterator yields
17
+ * arrays containing the values yielded by each of the provided iterators.
18
18
  *
19
19
  * @example ExtraIterator.zip([1, 2, 3], ['a', 'b', 'c']).toArray() // returns [ [1, 'a'], [2, 'b'], [3, 'c'] ]
20
20
  */
@@ -26,23 +26,35 @@ export declare class ExtraIterator<T> extends Iterator<T, any, any> {
26
26
  */
27
27
  static empty<T = any>(): ExtraIterator<T>;
28
28
  /**
29
- * Creates an iterator that yields incrementing numbers, starting from
30
- * `start` (default 0) and ending at `end`. (exclusive)
29
+ * Creates an iterator that yields incrementing numbers.
31
30
  *
32
- * If `end` is omitted, counts to Infinity.
31
+ * > This iterator is infinite. Use {@link take} method if you want a specific number of values.
33
32
  *
34
- * @example ExtraIterator.count(5).toArray() // returns [0, 1, 2, 3, 4]
33
+ * @example ExtraIterator.count().take(5).toArray() // returns [0, 1, 2, 3, 4]
35
34
  */
36
- static count(): ExtraIterator<number>;
37
- static count(end: number): ExtraIterator<number>;
38
- static count(start: number, end: number): ExtraIterator<number>;
39
- static count(start: number, end: number, interval: number): ExtraIterator<number>;
35
+ static count({ start, interval }?: {
36
+ start?: number | undefined;
37
+ interval?: number | undefined;
38
+ }): ExtraIterator<number>;
40
39
  /**
41
- * Creates an iterator that yields the provided value `count` times.
40
+ * Creates an iterator that repeatedly yields the provided value.
41
+ *
42
+ * > ⚠ This iterator is infinite. Use {@link take} method if you want a specific number of values.
42
43
  *
43
44
  * @example ExtraIterator.repeat(3, 'a').toArray() // returns ['a', 'a', 'a']
44
45
  */
45
- static repeat<T>(count: number, value: T): ExtraIterator<T>;
46
+ static repeat<T>(value: T): ExtraIterator<T>;
47
+ /**
48
+ * Generates random cryptographically strong random numbers.
49
+ *
50
+ * > ⚠ This iterator is infinite. Use {@link take} method if you want a specific number of values.
51
+ *
52
+ * @param param0
53
+ * @returns
54
+ */
55
+ static random({ bufferSize }?: {
56
+ bufferSize?: number | undefined;
57
+ }): ExtraIterator<number>;
46
58
  private constructor();
47
59
  private source;
48
60
  next(value?: any): IteratorResult<T, any>;
@@ -243,6 +255,14 @@ export declare class ExtraIterator<T> extends Iterator<T, any, any> {
243
255
  * Returns an iterator the provided element if this iterator is empty; otherwise, it returns this iterator.
244
256
  */
245
257
  defaultIfEmpty(provider: () => T): ExtraIterator<T>;
258
+ /**
259
+ * Creates a new iterator that yields the values of this iterator and then reiterates over the same values and
260
+ * yields each of them again, a number of times determined by the {@param times} parameter. If omitted, loops
261
+ * infinitely.
262
+ *
263
+ * @example ExtraIterator.from([1, 2, 3]).loop(3).toArray() // returns [1, 2, 3, 1, 2, 3, 1, 2, 3]
264
+ */
265
+ loop(times?: number): ExtraIterator<T>;
246
266
  /**
247
267
  * Returns the first element of the iterator, or `undefined` if the iterator is empty.
248
268
  */
@@ -263,6 +283,9 @@ export declare class ExtraIterator<T> extends Iterator<T, any, any> {
263
283
  * The returned object is composed of keys generated by calling the provided callback function on each element of
264
284
  * this iterator, and the value for each key is an array containing all the elements that were assigned to that key.
265
285
  *
286
+ * This method is similar to {@link toMap}, but the returned object is a plain, null-prototype, object, instead of a
287
+ * `Map`.
288
+ *
266
289
  * @example
267
290
  *
268
291
  * ExtraIterator.from([1, 2, 3, 4, 5])
@@ -271,6 +294,20 @@ export declare class ExtraIterator<T> extends Iterator<T, any, any> {
271
294
  * // returns { even: [2, 4], odd: [1, 3, 5] }
272
295
  */
273
296
  groupBy<K extends string | symbol>(callbackfn: (value: T, index: number) => K): Record<K, T[]>;
297
+ /**
298
+ * Groups elements into separate arrays and returns a Map containing each group.
299
+ *
300
+ * The returned Map is composed of keys generated by calling the provided callback function on each element of this
301
+ * iterator, and the value for each key is an array containing all the elements to which the callback function
302
+ * returned that key.
303
+ *
304
+ * This method is similart to {@link groupBy}, but the returned object is a Map instead of a plain object.
305
+ */
306
+ toMap<K extends string | symbol>(callbackfn: (value: T, index: number) => K): Map<K, T[]>;
307
+ /**
308
+ * Creates a set containing all the values yielded by this iterator.
309
+ */
310
+ toSet(): Set<T>;
274
311
  toChainOfResponsibilityFunction<ResultType = void | Promise<void>, ParamsType extends any[] = []>(invokeHandler: (handler: T, next: (...args: ParamsType) => ResultType, ...args: ParamsType) => ResultType): (...args: ParamsType) => ResultType;
275
312
  /**
276
313
  * Consumes the iterator and returns a value determined by calling the provided function using the iterator as
@@ -284,9 +321,10 @@ export declare class ExtraIterator<T> extends Iterator<T, any, any> {
284
321
  * // returns { _a: 2, _b: 4 }
285
322
  */
286
323
  collect<U>(collectfn: ((iter: Iterable<T>) => U)): U;
287
- toSortedBy(...keys: (keyof T)[]): T[];
288
324
  /**
289
325
  * Consumes the iterator and returns the number of elements it contained.
326
+ *
327
+ * @example ExtraIterator.from([1, 2, 3, 4]).count() // returns 4
290
328
  */
291
329
  count(): number;
292
330
  /**
package/dist/index.js CHANGED
@@ -29,28 +29,51 @@ export class ExtraIterator extends Iterator {
29
29
  static empty() {
30
30
  return new ExtraIterator([]);
31
31
  }
32
- static count(...args) {
33
- const [start, end, interval] = args.length === 0 ? [0, Infinity, 1]
34
- : args.length === 1 ? [0, args[0], 1]
35
- : [args[0], args[1], args[2] ?? 1];
32
+ /**
33
+ * Creates an iterator that yields incrementing numbers.
34
+ *
35
+ * > This iterator is infinite. Use {@link take} method if you want a specific number of values.
36
+ *
37
+ * @example ExtraIterator.count().take(5).toArray() // returns [0, 1, 2, 3, 4]
38
+ */
39
+ static count({ start = 0, interval = 1 } = {}) {
36
40
  return new ExtraIterator(function* () {
37
- for (let counter = start; counter < end; counter += interval) {
38
- yield counter;
41
+ while (true) {
42
+ yield start;
43
+ start += interval;
39
44
  }
40
45
  }());
41
46
  }
42
47
  /**
43
- * Creates an iterator that yields the provided value `count` times.
48
+ * Creates an iterator that repeatedly yields the provided value.
49
+ *
50
+ * > ⚠ This iterator is infinite. Use {@link take} method if you want a specific number of values.
44
51
  *
45
52
  * @example ExtraIterator.repeat(3, 'a').toArray() // returns ['a', 'a', 'a']
46
53
  */
47
- static repeat(count, value) {
54
+ static repeat(value) {
48
55
  return new ExtraIterator(function* () {
49
- for (let index = 0; index < count; index++) {
56
+ while (true) {
50
57
  yield value;
51
58
  }
52
59
  }());
53
60
  }
61
+ /**
62
+ * Generates random cryptographically strong random numbers.
63
+ *
64
+ * > ⚠ This iterator is infinite. Use {@link take} method if you want a specific number of values.
65
+ *
66
+ * @param param0
67
+ * @returns
68
+ */
69
+ static random({ bufferSize = 1024 } = {}) {
70
+ const buffer = new Uint8Array(bufferSize);
71
+ return new ExtraIterator(function* () {
72
+ globalThis.crypto.getRandomValues(buffer);
73
+ yield* new Float64Array(buffer);
74
+ }())
75
+ .loop();
76
+ }
54
77
  // =================================================================================================================
55
78
  // PRIVATES
56
79
  // =================================================================================================================
@@ -423,6 +446,24 @@ export class ExtraIterator extends Iterator {
423
446
  }
424
447
  }.call(this));
425
448
  }
449
+ /**
450
+ * Creates a new iterator that yields the values of this iterator and then reiterates over the same values and
451
+ * yields each of them again, a number of times determined by the {@param times} parameter. If omitted, loops
452
+ * infinitely.
453
+ *
454
+ * @example ExtraIterator.from([1, 2, 3]).loop(3).toArray() // returns [1, 2, 3, 1, 2, 3, 1, 2, 3]
455
+ */
456
+ loop(times = Infinity) {
457
+ return ExtraIterator.from(function* () {
458
+ const values = this.toArray();
459
+ if (values.length === 0) {
460
+ return;
461
+ }
462
+ for (let i = 0; i < times; i++) {
463
+ yield* values;
464
+ }
465
+ }.call(this));
466
+ }
426
467
  // =================================================================================================================
427
468
  // AGGREGATING FUNCTIONS
428
469
  // -----------------------------------------------------------------------------------------------------------------
@@ -463,6 +504,9 @@ export class ExtraIterator extends Iterator {
463
504
  * The returned object is composed of keys generated by calling the provided callback function on each element of
464
505
  * this iterator, and the value for each key is an array containing all the elements that were assigned to that key.
465
506
  *
507
+ * This method is similar to {@link toMap}, but the returned object is a plain, null-prototype, object, instead of a
508
+ * `Map`.
509
+ *
466
510
  * @example
467
511
  *
468
512
  * ExtraIterator.from([1, 2, 3, 4, 5])
@@ -481,6 +525,37 @@ export class ExtraIterator extends Iterator {
481
525
  }
482
526
  return result;
483
527
  }
528
+ /**
529
+ * Groups elements into separate arrays and returns a Map containing each group.
530
+ *
531
+ * The returned Map is composed of keys generated by calling the provided callback function on each element of this
532
+ * iterator, and the value for each key is an array containing all the elements to which the callback function
533
+ * returned that key.
534
+ *
535
+ * This method is similart to {@link groupBy}, but the returned object is a Map instead of a plain object.
536
+ */
537
+ toMap(callbackfn) {
538
+ const result = new Map();
539
+ for (let index = 0, next; next = this.next(), !next.done; index++) {
540
+ const key = callbackfn(next.value, index);
541
+ const array = result.get(key);
542
+ if (!array) {
543
+ result.set(key, [next.value]);
544
+ }
545
+ else {
546
+ array.push(next.value);
547
+ }
548
+ }
549
+ return result;
550
+ }
551
+ /**
552
+ * Creates a set containing all the values yielded by this iterator.
553
+ */
554
+ toSet() {
555
+ const result = new Set();
556
+ this.forEach(value => result.add(value));
557
+ return result;
558
+ }
484
559
  toChainOfResponsibilityFunction(invokeHandler) {
485
560
  const handlers = this.toArray();
486
561
  return (...initialArgs) => {
@@ -510,20 +585,10 @@ export class ExtraIterator extends Iterator {
510
585
  collect(collectfn) {
511
586
  return collectfn(this);
512
587
  }
513
- toSortedBy(...keys) {
514
- return this.toArray()
515
- .sort((a, b) => {
516
- for (const key of keys) {
517
- if (a[key] < b[key])
518
- return -1;
519
- if (a[key] > b[key])
520
- return 1;
521
- }
522
- return 0;
523
- });
524
- }
525
588
  /**
526
589
  * Consumes the iterator and returns the number of elements it contained.
590
+ *
591
+ * @example ExtraIterator.from([1, 2, 3, 4]).count() // returns 4
527
592
  */
528
593
  count() {
529
594
  let count = 0;
@@ -14,13 +14,22 @@ describe('ExtraIterator', () => {
14
14
  expect(zipped.toArray()).toEqual([[1, 'a'], [2, 'b'], [3, 'c']]);
15
15
  });
16
16
  it('should count from 0 to a given number', () => {
17
- const iterator = ExtraIterator.count(5);
17
+ const iterator = ExtraIterator.count().take(5);
18
18
  expect(iterator.toArray()).toEqual([0, 1, 2, 3, 4]);
19
19
  });
20
+ it('should count in 2s, starting from 5', () => {
21
+ const iterator = ExtraIterator.count({ start: 5, interval: 2 }).take(5);
22
+ expect(iterator.toArray()).toEqual([5, 7, 9, 11, 13]);
23
+ });
20
24
  it('should repeat a value a given number of times', () => {
21
- const iterator = ExtraIterator.repeat(3, 'x');
25
+ const iterator = ExtraIterator.repeat('x').take(3);
22
26
  expect(iterator.toArray()).toEqual(['x', 'x', 'x']);
23
27
  });
28
+ it('should yield random values', () => {
29
+ const values = ExtraIterator.random().take(5).toArray();
30
+ expect(values.length).toBe(5);
31
+ expect(values.every(value => typeof value === 'number')).toBe(true);
32
+ });
24
33
  it('should filter values based on a predicate', () => {
25
34
  const iterator = ExtraIterator.from([1, 2, 3, 4]).filter(x => x % 2 === 0);
26
35
  expect(iterator.toArray()).toEqual([2, 4]);
@@ -117,6 +126,25 @@ describe('ExtraIterator', () => {
117
126
  b: ['banana'],
118
127
  });
119
128
  });
129
+ it('should convert to a Map', () => {
130
+ const iterator = ExtraIterator.from([{ key: 'a', value: 1 }, { key: 'b', value: 2 }, { key: 'a', value: 3 }]);
131
+ const map = iterator.toMap(item => item.key);
132
+ expect(map).toBeInstanceOf(Map);
133
+ expect(map).toEqual(new Map([
134
+ ['a', [{ key: 'a', value: 1 }, { key: 'a', value: 3 }]],
135
+ ['b', [{ key: 'b', value: 2 }]],
136
+ ]));
137
+ });
138
+ it('should convert to a Set', () => {
139
+ const iterator = ExtraIterator.from([3, 1, 3, 2, 2, 1, 3]);
140
+ const set = iterator.toSet();
141
+ expect(set).toBeInstanceOf(Set);
142
+ expect(set.size).toBe(3);
143
+ expect(set.has(1)).toBe(true);
144
+ expect(set.has(2)).toBe(true);
145
+ expect(set.has(3)).toBe(true);
146
+ expect(set).toEqual(new Set([3, 1, 2]));
147
+ });
120
148
  it('should collect values using a custom collector', () => {
121
149
  const iterator = ExtraIterator.from([1, 2, 3]);
122
150
  const sum = iterator.collect(iter => Array.from(iter).reduce((a, b) => a + b, 0));
@@ -141,4 +169,8 @@ describe('ExtraIterator', () => {
141
169
  const chain = handlers.toChainOfResponsibilityFunction(next => next());
142
170
  expect(() => chain()).toThrow();
143
171
  });
172
+ it('should repeat values', () => {
173
+ const iterator = ExtraIterator.from([1, 2, 3]).loop(3);
174
+ expect(iterator.toArray()).toEqual([1, 2, 3, 1, 2, 3, 1, 2, 3]);
175
+ });
144
176
  });
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.5.0",
6
+ "version": "0.7.0",
7
7
  "type": "module",
8
8
  "exports": {
9
9
  ".": "./dist/index.js",
File without changes
@@ -1 +0,0 @@
1
- "use strict";