@bodil/monkey-business 0.1.0 → 0.1.1
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/package.json +3 -2
- package/src/index.test.ts +116 -0
- package/src/index.ts +380 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bodil/monkey-business",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Let's give JS core types a polish",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"module": "dist/index.js",
|
|
11
11
|
"types": "dist/index.d.ts",
|
|
12
12
|
"files": [
|
|
13
|
-
"dist"
|
|
13
|
+
"dist",
|
|
14
|
+
"src"
|
|
14
15
|
],
|
|
15
16
|
"exports": {
|
|
16
17
|
".": {
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { test, expect, expectTypeOf } from "vitest";
|
|
2
|
+
import type { Option } from "@bodil/opt";
|
|
3
|
+
import { Order } from "@bodil/core";
|
|
4
|
+
|
|
5
|
+
import ".";
|
|
6
|
+
|
|
7
|
+
import "@bodil/opt-vitest";
|
|
8
|
+
|
|
9
|
+
const Iterator = globalThis.Iterator;
|
|
10
|
+
|
|
11
|
+
test("Object.get", () => {
|
|
12
|
+
const obj = { foo: "foo", bar: 31337 };
|
|
13
|
+
expect(Object.get(obj, "foo")).isSome("foo");
|
|
14
|
+
expectTypeOf(Object.get(obj, "foo")).toEqualTypeOf<Option<string>>();
|
|
15
|
+
expect(Object.get(obj, "bar")).isSome(31337);
|
|
16
|
+
expectTypeOf(Object.get(obj, "bar")).toEqualTypeOf<Option<number>>();
|
|
17
|
+
// @ts-expect-error
|
|
18
|
+
expect(Object.get(obj, "baz")).isNone();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("Array.get", () => {
|
|
22
|
+
const array = [4, 5, 6];
|
|
23
|
+
expect(array.get(-1)).isNone();
|
|
24
|
+
expect(array.get(0)).isSome(4);
|
|
25
|
+
expect(array.get(1)).isSome(5);
|
|
26
|
+
expect(array.get(2)).isSome(6);
|
|
27
|
+
expect(array.get(3)).isNone();
|
|
28
|
+
|
|
29
|
+
const sparseArray: Array<number> = [];
|
|
30
|
+
sparseArray[1] = 31337;
|
|
31
|
+
expect(sparseArray.get(0)).isNone();
|
|
32
|
+
expect(sparseArray.get(1)).isSome(31337);
|
|
33
|
+
expect(sparseArray.get(2)).isNone();
|
|
34
|
+
expectTypeOf(sparseArray.get(0)).toEqualTypeOf<Option<number>>();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("Object.mapEntries", () => {
|
|
38
|
+
const obj1 = { foo: 1, bar: 2, baz: 3 };
|
|
39
|
+
expect(Object.mapEntries(obj1, ([key, value]) => [key.toUpperCase(), `${value + 1}`])).toEqual({
|
|
40
|
+
FOO: "2",
|
|
41
|
+
BAR: "3",
|
|
42
|
+
BAZ: "4",
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("Map.getOrSet", () => {
|
|
47
|
+
const defaultValue = () => "Robert";
|
|
48
|
+
const map = new Map();
|
|
49
|
+
map.set("foo", "Joe");
|
|
50
|
+
expect(map.getOrSet("foo", defaultValue)).toEqual("Joe");
|
|
51
|
+
expect(map.getOrSet("bar", defaultValue)).toEqual("Robert");
|
|
52
|
+
expect(map.get("bar")).toEqual("Robert");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("Array.insert", () => {
|
|
56
|
+
const array = [1, 2, 3, 4, 5];
|
|
57
|
+
const result = array.insert(1337, 3);
|
|
58
|
+
expect(result).toEqual([1, 2, 3, 1337, 4, 5]);
|
|
59
|
+
expect(array).toEqual([1, 2, 3, 1337, 4, 5]);
|
|
60
|
+
expect(result).toBe(array);
|
|
61
|
+
|
|
62
|
+
expect(() => array.insert(1337, 10)).toThrow(RangeError);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("Array.insertOrdered", () => {
|
|
66
|
+
const array = [1, 3, 5, 7, 9];
|
|
67
|
+
const result = array.insertOrdered(6, Order.ascending);
|
|
68
|
+
expect(result).toEqual([1, 3, 5, 6, 7, 9]);
|
|
69
|
+
expect(array).toEqual([1, 3, 5, 6, 7, 9]);
|
|
70
|
+
const result2 = array.insertOrdered(1337, Order.ascending);
|
|
71
|
+
expect(result2).toEqual([1, 3, 5, 6, 7, 9, 1337]);
|
|
72
|
+
expect(array).toEqual([1, 3, 5, 6, 7, 9, 1337]);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("Array.remove", () => {
|
|
76
|
+
const array = [1, 2, 3, 4, 5];
|
|
77
|
+
expect(array.remove(3)).isSome(3);
|
|
78
|
+
expect(array).toEqual([1, 2, 4, 5]);
|
|
79
|
+
expect(array.remove(6)).isNone();
|
|
80
|
+
expect(array).toEqual([1, 2, 4, 5]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("Array.filterPresent", () => {
|
|
84
|
+
const array: Array<number | undefined> = [1, 2, undefined, 3, undefined, 4];
|
|
85
|
+
const cleanArray = array.present();
|
|
86
|
+
expect(array.some((v) => v === undefined)).toBeTruthy();
|
|
87
|
+
expect(cleanArray.some((v) => v === undefined)).toBeFalsy();
|
|
88
|
+
expect(cleanArray).toEqual([1, 2, 3, 4]);
|
|
89
|
+
expectTypeOf(cleanArray).toMatchTypeOf<Array<number>>();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("Iterator.partition", () => {
|
|
93
|
+
expect(Array.from(Iterator.from([1, 2, 3, 4]).partition(2))).toEqual([
|
|
94
|
+
[1, 2],
|
|
95
|
+
[3, 4],
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
expect(Array.from(Iterator.from([1, 2, 3]).partition(2))).toEqual([[1, 2], [3]]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("Iterator.frontBiasedPartition", () => {
|
|
102
|
+
expect(Array.from(Iterator.from([1, 2, 3, 4]).frontBiasedPartition(2))).toEqual([
|
|
103
|
+
[1, 2],
|
|
104
|
+
[3, 4],
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
expect(Array.from(Iterator.from([1, 2, 3]).frontBiasedPartition(2))).toEqual([[1], [2, 3]]);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("Iterator.takeOne", () => {
|
|
111
|
+
const iter = [1, 2, 3][Symbol.iterator]();
|
|
112
|
+
expect(iter.takeOne()).isSome(1);
|
|
113
|
+
expect(iter.takeOne()).isSome(2);
|
|
114
|
+
expect(iter.takeOne()).isSome(3);
|
|
115
|
+
expect(iter.takeOne()).isNone();
|
|
116
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-this-alias */
|
|
2
|
+
// deno-lint-ignore-file no-this-alias
|
|
3
|
+
|
|
4
|
+
import { None, Option, Some } from "@bodil/opt";
|
|
5
|
+
import { type OrderFn, bisectHigh, bisectLow } from "@bodil/core/order";
|
|
6
|
+
import type { Present } from "@bodil/core/types";
|
|
7
|
+
import { assert } from "@bodil/core/assert";
|
|
8
|
+
|
|
9
|
+
declare global {
|
|
10
|
+
interface ObjectConstructor {
|
|
11
|
+
/**
|
|
12
|
+
* Checked key lookup. Returns {@link None} if a key isn't present.
|
|
13
|
+
* Returns a {@link Some} if the key is present, even if the value is
|
|
14
|
+
* `undefined`.
|
|
15
|
+
*/
|
|
16
|
+
get<O extends object, K extends keyof O>(obj: O, key: K): Option<O[K]>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create a new object by mapping an existing object's `Object.entries`
|
|
20
|
+
* through a function.
|
|
21
|
+
*/
|
|
22
|
+
mapEntries<A, B>(
|
|
23
|
+
obj: Record<string, A>,
|
|
24
|
+
fn: (entry: [key: string, value: A]) => [string, B]
|
|
25
|
+
): Record<string, B>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface Map<K, V> {
|
|
29
|
+
/**
|
|
30
|
+
* If `key` exists in the map, return the value associated with it.
|
|
31
|
+
* Otherwise, call `value()` to create a new value, insert that into the
|
|
32
|
+
* map under `key`, and return it.
|
|
33
|
+
*/
|
|
34
|
+
getOrSet(key: K, defaultValue: () => V): V;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface Array<T> {
|
|
38
|
+
/**
|
|
39
|
+
* Insert `value` at `index` in the array.
|
|
40
|
+
*/
|
|
41
|
+
insert(value: T, index: number): Array<T>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Insert `value` into the array at the correct position according to
|
|
45
|
+
* the ordering function `cmp`. The array must already be ordered
|
|
46
|
+
* accordingly.
|
|
47
|
+
*
|
|
48
|
+
* If `duplicates` is `"low"`, the correct position in case of
|
|
49
|
+
* duplicates is considered to be the index of the first occurrence of a
|
|
50
|
+
* duplicate. If it is `"high"`, which is the default, the correct
|
|
51
|
+
* position is considered to be the index after the last occurrence of a
|
|
52
|
+
* duplicate.
|
|
53
|
+
*/
|
|
54
|
+
insertOrdered(value: T, cmp: OrderFn<T>, duplicates?: "low" | "high"): Array<T>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Remove the first occurrence of a given value from an array.
|
|
58
|
+
*
|
|
59
|
+
* Returns an {@link Option} containing the removed value, or {@link None} if
|
|
60
|
+
* no matches were found.
|
|
61
|
+
*/
|
|
62
|
+
remove(value: T): Option<T>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Remove the first value for which the provided predicate function
|
|
66
|
+
* returns `true` from the array.
|
|
67
|
+
*
|
|
68
|
+
* Returns an {@link Option} containing the removed value, or {@link None} if
|
|
69
|
+
* no matches were found.
|
|
70
|
+
*/
|
|
71
|
+
removeFn(predicate: (value: T, index: number, obj: Array<T>) => boolean): Option<T>;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Remove the value at the given index from the array.
|
|
75
|
+
*
|
|
76
|
+
* Returns an {@link Option} containing the removed value, or {@link None} if
|
|
77
|
+
* the index was out of bounds.
|
|
78
|
+
*/
|
|
79
|
+
removeIndex(index: number): Option<T>;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Return a copy of the array with any `undefined` values removed.
|
|
83
|
+
*/
|
|
84
|
+
present(): Array<Present<T>>;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Return a copy of the array with any `null` or `undefined` values removed.
|
|
88
|
+
*/
|
|
89
|
+
nonNullable(): Array<NonNullable<T>>;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Checked index operator. Returns {@link None} if an index isn't
|
|
93
|
+
* present, even for sparse arrays. Returns a {@link Some} if the index
|
|
94
|
+
* is present, even if the value is `undefined`.
|
|
95
|
+
*/
|
|
96
|
+
get(index: number): Option<T>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface IteratorConstructor {
|
|
100
|
+
/**
|
|
101
|
+
* Construct an empty iterator.
|
|
102
|
+
*/
|
|
103
|
+
empty<T>(): IteratorObject<T>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
107
|
+
interface IteratorObject<T, TReturn, TNext> {
|
|
108
|
+
/**
|
|
109
|
+
* Get the next value from the iterator, wrapped in an {@link Option}
|
|
110
|
+
* type. If the iterator has no more values, return {@link None}.
|
|
111
|
+
*
|
|
112
|
+
* This is the nicely utility typed version of {@link Iterator#next}.
|
|
113
|
+
*/
|
|
114
|
+
takeOne(): Option<T>;
|
|
115
|
+
/**
|
|
116
|
+
* Take items from the iterator only until the first time `predicate` returns false.
|
|
117
|
+
*/
|
|
118
|
+
takeWhile<S extends T>(
|
|
119
|
+
predicate: (value: T, index: number) => value is S
|
|
120
|
+
): IteratorObject<S, undefined>;
|
|
121
|
+
takeWhile(predicate: (value: T, index: number) => boolean): IteratorObject<T, undefined>;
|
|
122
|
+
/**
|
|
123
|
+
* Ignore all items matching `predicate` until the first item that
|
|
124
|
+
* doesn't match.
|
|
125
|
+
*/
|
|
126
|
+
skipWhile(predicate: (value: T, index: number) => boolean): IteratorObject<T, undefined>;
|
|
127
|
+
/**
|
|
128
|
+
* Iterate until calling `mapFn` on an item returns a value, then return
|
|
129
|
+
* that value. Return `undefined` if `mapFn` never returns a value.
|
|
130
|
+
*/
|
|
131
|
+
findMap<U>(mapFn: (value: T) => NonNullable<U> | undefined): NonNullable<U> | undefined;
|
|
132
|
+
/**
|
|
133
|
+
* Split the input up into arrays of at most `size` items.
|
|
134
|
+
*/
|
|
135
|
+
partition(size: number): IteratorObject<Array<T>, undefined>;
|
|
136
|
+
/**
|
|
137
|
+
* As {@link IteratorObject#partition}, but if the input length isn't
|
|
138
|
+
* divisible by `size`, ensure the *first* array is the shortest one
|
|
139
|
+
* rather than the last.
|
|
140
|
+
*
|
|
141
|
+
* Be warned that this requires the entire input iterable to be read up
|
|
142
|
+
* front to decide its length, so this function is not lazy.
|
|
143
|
+
*/
|
|
144
|
+
frontBiasedPartition(size: number): Array<Array<T>>;
|
|
145
|
+
/**
|
|
146
|
+
* Filter out any items which are `undefined`.
|
|
147
|
+
*/
|
|
148
|
+
present(): IteratorObject<Present<T>, undefined>;
|
|
149
|
+
/**
|
|
150
|
+
* Filter out any items which are `null` or `undefined`.
|
|
151
|
+
*/
|
|
152
|
+
nonNullable(): IteratorObject<NonNullable<T>, undefined>;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Object
|
|
157
|
+
|
|
158
|
+
Object.get = function get<O extends object, K extends keyof O>(obj: O, key: K): Option<O[K]> {
|
|
159
|
+
return Object.hasOwn(obj, key) ? Some(obj[key]) : None;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
Object.mapEntries = function mapEntries<A, B>(
|
|
163
|
+
obj: Record<string, A>,
|
|
164
|
+
fn: (entry: [key: string, value: A]) => [string, B]
|
|
165
|
+
): Record<string, B> {
|
|
166
|
+
return Object.fromEntries(Object.entries(obj).map(fn));
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Map
|
|
170
|
+
|
|
171
|
+
Map.prototype.getOrSet = function getOrSet<K, V>(
|
|
172
|
+
this: Map<K, NonNullable<V>>,
|
|
173
|
+
key: K,
|
|
174
|
+
defaultValue: () => NonNullable<V>
|
|
175
|
+
): V {
|
|
176
|
+
const result = this.get(key);
|
|
177
|
+
if (result !== undefined) {
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
const newValue = defaultValue();
|
|
181
|
+
this.set(key, newValue);
|
|
182
|
+
return newValue;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// Array
|
|
186
|
+
|
|
187
|
+
Array.prototype.remove = function remove<T>(this: Array<T>, value: T): Option<T> {
|
|
188
|
+
return this.removeIndex(this.indexOf(value));
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
Array.prototype.removeFn = function remove<T>(
|
|
192
|
+
this: Array<T>,
|
|
193
|
+
predicate: (value: T, index: number, obj: Array<T>) => boolean
|
|
194
|
+
): Option<T> {
|
|
195
|
+
return this.removeIndex(this.findIndex(predicate as () => boolean));
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
Array.prototype.removeIndex = function remove<T>(this: Array<T>, index: number): Option<T> {
|
|
199
|
+
if (!Number.isInteger(index)) {
|
|
200
|
+
throw new TypeError(`Array.removeIndex(): index ${index} is not an integer`);
|
|
201
|
+
}
|
|
202
|
+
if (index < 0 || index >= this.length) {
|
|
203
|
+
return None;
|
|
204
|
+
}
|
|
205
|
+
const removed = this.splice(index, 1).pop();
|
|
206
|
+
return Option.from(removed);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
Array.prototype.insert = function insert<T>(this: Array<T>, value: T, index: number): Array<T> {
|
|
210
|
+
if (!Number.isInteger(index)) {
|
|
211
|
+
throw new TypeError(`Array.insert(): index ${index} is not an integer`);
|
|
212
|
+
}
|
|
213
|
+
if (index > this.length || index < 0) {
|
|
214
|
+
throw new RangeError(`Array.insert: index ${index} out of bounds`);
|
|
215
|
+
}
|
|
216
|
+
this.splice(index, 0, value);
|
|
217
|
+
return this;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
Array.prototype.insertOrdered = function insertOrdered<T>(
|
|
221
|
+
this: Array<T>,
|
|
222
|
+
value: T,
|
|
223
|
+
cmp: OrderFn<T>,
|
|
224
|
+
duplicates: "low" | "high" = "high"
|
|
225
|
+
): Array<T> {
|
|
226
|
+
return this.insert(value, (duplicates === "low" ? bisectLow : bisectHigh)(cmp, this, value));
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
Array.prototype.present = function present<T>(this: Array<T>): Array<Present<T>> {
|
|
230
|
+
return this.filter((value: T): value is Present<T> => value !== undefined);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
Array.prototype.nonNullable = function nonNullable<T>(this: Array<T>): Array<NonNullable<T>> {
|
|
234
|
+
return this.filter((value: T): value is NonNullable<T> => value !== undefined);
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
Array.prototype.get = function get<T>(this: Array<T>, index: number): Option<T> {
|
|
238
|
+
return Object.get(this, index);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// Iterator
|
|
242
|
+
|
|
243
|
+
Iterator.empty = function empty<T>(): IteratorObject<T> {
|
|
244
|
+
return Iterator.from([]);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
Iterator.prototype.takeOne = function takeOne<T>(this: Iterator<T>): Option<T> {
|
|
248
|
+
const result = this.next();
|
|
249
|
+
return result.done === true ? None : Some(result.value);
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
Iterator.prototype.takeWhile = function takeWhile<T>(
|
|
253
|
+
this: IteratorObject<T, undefined>,
|
|
254
|
+
predicate: (value: T, index: number) => boolean
|
|
255
|
+
): IteratorObject<T, undefined> {
|
|
256
|
+
const iter = this;
|
|
257
|
+
let index = 0;
|
|
258
|
+
let done = false;
|
|
259
|
+
return Iterator.from<T>({
|
|
260
|
+
next(): IteratorResult<T, undefined> {
|
|
261
|
+
if (!done) {
|
|
262
|
+
const result = iter.next();
|
|
263
|
+
if (result.done === true) {
|
|
264
|
+
return result;
|
|
265
|
+
}
|
|
266
|
+
if (predicate(result.value, index++)) {
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
done = true;
|
|
271
|
+
return { done: true, value: undefined };
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
Iterator.prototype.skipWhile = function skipWhile<T>(
|
|
277
|
+
this: IteratorObject<T, undefined>,
|
|
278
|
+
predicate: (value: T, index: number) => boolean
|
|
279
|
+
): IteratorObject<T, undefined> {
|
|
280
|
+
const iter = this;
|
|
281
|
+
let index = 0;
|
|
282
|
+
let skipped = false;
|
|
283
|
+
return Iterator.from<T>({
|
|
284
|
+
next(): IteratorResult<T, undefined> {
|
|
285
|
+
if (skipped) {
|
|
286
|
+
return iter.next();
|
|
287
|
+
}
|
|
288
|
+
while (true) {
|
|
289
|
+
const result = iter.next();
|
|
290
|
+
if (result.done === true) {
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
if (!predicate(result.value, index++)) {
|
|
294
|
+
skipped = true;
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
Iterator.prototype.findMap = function findMap<T, U>(
|
|
303
|
+
this: IteratorObject<T, undefined>,
|
|
304
|
+
mapFn: (value: T, index: number) => NonNullable<U> | undefined
|
|
305
|
+
): NonNullable<U> | undefined {
|
|
306
|
+
let index = 0;
|
|
307
|
+
while (true) {
|
|
308
|
+
const result = this.next();
|
|
309
|
+
if (result.done === true) {
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
const mapped = mapFn(result.value, index++);
|
|
313
|
+
if (mapped !== undefined) {
|
|
314
|
+
return mapped;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
Iterator.prototype.partition = function partition<T>(
|
|
320
|
+
this: IteratorObject<T, undefined>,
|
|
321
|
+
size: number
|
|
322
|
+
): IteratorObject<Array<T>, undefined> {
|
|
323
|
+
const iter = this;
|
|
324
|
+
let done = false;
|
|
325
|
+
return Iterator.from<Array<T>>({
|
|
326
|
+
next(): IteratorResult<Array<T>, undefined> {
|
|
327
|
+
if (done) {
|
|
328
|
+
return { done: true, value: undefined };
|
|
329
|
+
}
|
|
330
|
+
const part = [];
|
|
331
|
+
while (true) {
|
|
332
|
+
const result = iter.next();
|
|
333
|
+
if (result.done === true) {
|
|
334
|
+
done = true;
|
|
335
|
+
return part.length > 0
|
|
336
|
+
? { done: false, value: part }
|
|
337
|
+
: { done: true, value: undefined };
|
|
338
|
+
}
|
|
339
|
+
part.push(result.value);
|
|
340
|
+
if (part.length === size) {
|
|
341
|
+
return { done: false, value: part };
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
Iterator.prototype.frontBiasedPartition = function frontBiasedPartition<T>(
|
|
349
|
+
this: IteratorObject<T, undefined>,
|
|
350
|
+
size: number
|
|
351
|
+
): Array<Array<T>> {
|
|
352
|
+
const input = this.toArray();
|
|
353
|
+
let inputPos = 0;
|
|
354
|
+
const firstLength = input.length % size;
|
|
355
|
+
const output: Array<Array<T>> = [];
|
|
356
|
+
if (firstLength > 0) {
|
|
357
|
+
output.push(input.slice(0, firstLength));
|
|
358
|
+
inputPos = firstLength;
|
|
359
|
+
}
|
|
360
|
+
while (inputPos < input.length) {
|
|
361
|
+
output.push(input.slice(inputPos, inputPos + size));
|
|
362
|
+
inputPos += size;
|
|
363
|
+
}
|
|
364
|
+
assert(inputPos === input.length);
|
|
365
|
+
return output;
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
Iterator.prototype.present = function present<T>(
|
|
369
|
+
this: IteratorObject<T, undefined>
|
|
370
|
+
): IteratorObject<Present<T>, undefined> {
|
|
371
|
+
return Iterator.from(this.filter((item): item is Present<T> => item !== undefined));
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
Iterator.prototype.nonNullable = function nonNullable<T>(
|
|
375
|
+
this: IteratorObject<T, undefined>
|
|
376
|
+
): IteratorObject<NonNullable<T>, undefined> {
|
|
377
|
+
return Iterator.from(
|
|
378
|
+
this.filter((item): item is NonNullable<T> => item !== undefined && item !== null)
|
|
379
|
+
);
|
|
380
|
+
};
|