@bodil/monkey-business 0.3.4 → 0.3.5

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/src/index.ts CHANGED
@@ -1,37 +1,27 @@
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";
1
+ import type { OrderFn } from "@bodil/core/order";
6
2
  import type { Present } from "@bodil/core/types";
7
- import { assert } from "@bodil/core/assert";
3
+ import type { Option } from "@bodil/opt";
8
4
  import defineProperties from "define-properties";
9
5
  import shimUnscopables from "es-shim-unscopables";
10
6
 
11
- import "es-iterator-helpers/Iterator.concat/auto";
12
- import "es-iterator-helpers/Iterator.zip/auto";
13
- import "es-iterator-helpers/Iterator.zipKeyed/auto";
14
- import "es-iterator-helpers/Iterator.prototype.chunks/auto";
7
+ import * as array from "./array";
8
+ import * as iterator from "./iterator";
9
+ import * as map from "./map";
10
+ import * as object from "./object";
11
+ import * as weakmap from "./weakmap";
15
12
 
16
13
  declare global {
17
14
  /**
18
15
  * Added methods on the {@link Object} global object.
19
16
  */
20
17
  interface ObjectConstructor {
21
- /**
22
- * Checked key lookup. Returns {@link None} if a key isn't present.
23
- * Returns a {@link Some} if the key is present, even if the value is
24
- * `undefined`.
25
- */
18
+ /** {@inheritDoc object.get} */
26
19
  get<O extends object, K extends keyof O>(obj: O, key: K): Option<O[K]>;
27
20
 
28
- /**
29
- * Create a new object by mapping an existing object's `Object.entries`
30
- * through a function.
31
- */
21
+ /** {@inheritDoc object.mapEntries} */
32
22
  mapEntries<A, B>(
33
23
  obj: Record<string, A>,
34
- fn: (entry: [key: string, value: A]) => [string, B]
24
+ fn: (entry: [key: string, value: A]) => [string, B],
35
25
  ): Record<string, B>;
36
26
  }
37
27
 
@@ -39,19 +29,13 @@ declare global {
39
29
  * Added methods on {@link Map}s.
40
30
  */
41
31
  interface Map<K, V> {
42
- /**
43
- * If `key` exists in the map, return the value associated with it.
44
- * Otherwise, call `defaultValue()` to create a new value, insert that
45
- * into the map under `key`, and return it.
46
- */
32
+ /** {@inheritDoc map.getOrInsertComputed} */
47
33
  getOrInsertComputed(key: K, defaultValue: (key: K) => V): V;
48
34
 
49
- /**
50
- * If `key` exists in the map, remove the key/value pair from the map
51
- * and return the removed value. Otherwise, return {@link None}.
52
- *
53
- * @see {@link Map.delete}
54
- */
35
+ /** {@inheritDoc map.getOrSet} */
36
+ getOrSet(key: K, defaultValue: (key: K) => V): V;
37
+
38
+ /** {@inheritDoc map.remove} */
55
39
  remove(key: K): Option<V>;
56
40
  }
57
41
 
@@ -59,19 +43,13 @@ declare global {
59
43
  * Added methods on {@link WeakMap}s.
60
44
  */
61
45
  interface WeakMap<K extends WeakKey, V> {
62
- /**
63
- * If `key` exists in the map, return the value associated with it.
64
- * Otherwise, call `defaultValue()` to create a new value, insert that
65
- * into the map under `key`, and return it.
66
- */
46
+ /** {@inheritDoc weakmap.getOrInsertComputed} */
67
47
  getOrInsertComputed(key: K, defaultValue: (key: K) => V): V;
68
48
 
69
- /**
70
- * If `key` exists in the map, remove the key/value pair from the map
71
- * and return the removed value. Otherwise, return {@link None}.
72
- *
73
- * @see {@link WeakMap.delete}
74
- */
49
+ /** {@inheritDoc weakmap.getOrSet} */
50
+ getOrSet(key: K, defaultValue: (key: K) => V): V;
51
+
52
+ /** {@inheritDoc weakmap.remove} */
75
53
  remove(key: K): Option<V>;
76
54
  }
77
55
 
@@ -79,69 +57,31 @@ declare global {
79
57
  * Added methods on {@link Array}s.
80
58
  */
81
59
  interface Array<T> {
82
- /**
83
- * Insert `value` at `index` in the array.
84
- */
60
+ /** {@inheritDoc array.insert} */
85
61
  insert(value: T, index: number): Array<T>;
86
62
 
87
- /**
88
- * Insert `value` into the array at the correct position according to
89
- * the ordering function `cmp`. The array must already be ordered
90
- * accordingly.
91
- *
92
- * If `duplicates` is `"low"`, the correct position in case of
93
- * duplicates is considered to be the index of the first occurrence of a
94
- * duplicate. If it is `"high"`, which is the default, the correct
95
- * position is considered to be the index after the last occurrence of a
96
- * duplicate.
97
- */
63
+ /** {@inheritDoc array.insertOrdered} */
98
64
  insertOrdered(value: T, cmp: OrderFn<T>, duplicates?: "low" | "high"): Array<T>;
99
65
 
100
- /**
101
- * Remove the first occurrence of a given value from an array.
102
- *
103
- * Returns an {@link Option} containing the removed value, or {@link None} if
104
- * no matches were found.
105
- */
66
+ /** {@inheritDoc array.remove} */
106
67
  remove(value: T): Option<T>;
107
68
 
108
- /**
109
- * Remove the first value for which the provided predicate function
110
- * returns `true` from the array.
111
- *
112
- * Returns an {@link Option} containing the removed value, or {@link None} if
113
- * no matches were found.
114
- */
69
+ /** {@inheritDoc array.removeFn} */
115
70
  removeFn(predicate: (value: T, index: number, obj: Array<T>) => boolean): Option<T>;
116
71
 
117
- /**
118
- * Remove the value at the given index from the array.
119
- *
120
- * Returns an {@link Option} containing the removed value, or {@link None} if
121
- * the index was out of bounds.
122
- */
72
+ /** {@inheritDoc array.removeIndex} */
123
73
  removeIndex(index: number): Option<T>;
124
74
 
125
- /**
126
- * Return a copy of the array with any `undefined` values removed.
127
- */
75
+ /** {@inheritDoc array.present} */
128
76
  present(): Array<Present<T>>;
129
77
 
130
- /**
131
- * Return a copy of the array with any `null` or `undefined` values removed.
132
- */
78
+ /** {@inheritDoc array.nonNullable} */
133
79
  nonNullable(): Array<NonNullable<T>>;
134
80
 
135
- /**
136
- * Checked index operator. Returns {@link None} if an index isn't
137
- * present, even for sparse arrays. Returns a {@link Some} if the index
138
- * is present, even if the value is `undefined`.
139
- */
81
+ /** {@inheritDoc array.get} */
140
82
  get(index: number): Option<T>;
141
83
 
142
- /**
143
- * Test whether a value is an array with the same contents as this one.
144
- */
84
+ /** {@inheritDoc array.equals} */
145
85
  equals<U = unknown>(other: unknown, equalsFn?: (a: T, b: U) => boolean): other is Array<T>;
146
86
  }
147
87
 
@@ -149,22 +89,13 @@ declare global {
149
89
  * Added methods on the {@link Iterator} global object.
150
90
  */
151
91
  interface IteratorConstructor {
152
- /**
153
- * Construct an empty iterator.
154
- */
92
+ /** {@inheritDoc iterator.empty} */
155
93
  empty<T>(): IteratorObject<T>;
156
- /**
157
- * Sequence multiple iterators into a single one.
158
- * @see https://github.com/tc39/proposal-iterator-sequencing
159
- */
94
+ /** {@inheritDoc iterator.concat} */
160
95
  concat<T>(...inputs: Array<Iterable<T>>): IteratorObject<T>;
161
- /**
162
- * @see https://github.com/tc39/proposal-joint-iteration
163
- */
96
+ /** {@inheritDoc iterator.zip} */
164
97
  zip<T>(inputs: Iterable<Iterable<T>>): IteratorObject<Array<T>>;
165
- /**
166
- * @see https://github.com/tc39/proposal-joint-iteration
167
- */
98
+ /** {@inheritDoc iterator.zipKeyed} */
168
99
  zipKeyed<T>(inputs: Record<string, Iterable<T>>): IteratorObject<Record<string, T>>;
169
100
  }
170
101
 
@@ -173,67 +104,32 @@ declare global {
173
104
  */
174
105
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
175
106
  interface IteratorObject<T, TReturn, TNext> {
176
- /**
177
- * Get the next value from the iterator, wrapped in an {@link Option}
178
- * type. If the iterator has no more values, return {@link None}.
179
- */
107
+ /** {@inheritDoc iterator.takeOne} */
180
108
  takeOne(): Option<T>;
181
- /**
182
- * Take items from the iterator only until the first time `predicate` returns false.
183
- */
109
+ /** {@inheritDoc iterator.takeWhile} */
184
110
  takeWhile<S extends T>(
185
- predicate: (value: T, index: number) => value is S
111
+ predicate: (value: T, index: number) => value is S,
186
112
  ): IteratorObject<S, undefined>;
187
113
  /** @ignore */
188
114
  takeWhile(predicate: (value: T, index: number) => boolean): IteratorObject<T, undefined>;
189
- /**
190
- * Ignore all items matching `predicate` until the first item that
191
- * doesn't match.
192
- */
115
+ /** {@inheritDoc iterator.skipWhile} */
193
116
  skipWhile(predicate: (value: T, index: number) => boolean): IteratorObject<T, undefined>;
194
- /**
195
- * Iterate until calling `mapFn` on an item returns a value, then return
196
- * that value. Return `undefined` if `mapFn` never returns a value.
197
- */
117
+ /** {@inheritDoc iterator.findMap} */
198
118
  findMap<U>(mapFn: (value: T) => NonNullable<U> | undefined): NonNullable<U> | undefined;
199
- /**
200
- * Split the input up into arrays of at most `size` items.
201
- */
119
+ /** {@inheritDoc iterator.chunks} */
202
120
  chunks(size: number): IteratorObject<Array<T>, undefined>;
203
- /**
204
- * Split the input up into arrays of at most `size` items.
205
- *
206
- * @deprecated This has been standardised as {@link IteratorObject#chunks}.
207
- */
121
+ /** {@inheritDoc iterator.partition} */
208
122
  partition(size: number): IteratorObject<Array<T>, undefined>;
209
- /**
210
- * As {@link IteratorObject#partition}, but if the input length isn't
211
- * divisible by `size`, ensure the *first* array is the shortest one
212
- * rather than the last.
213
- *
214
- * Be warned that this requires the entire input iterable to be read up
215
- * front to decide its length, so this function is not lazy.
216
- */
123
+ /** {@inheritDoc iterator.frontBiasedPartition} */
217
124
  frontBiasedPartition(size: number): Array<Array<T>>;
218
- /**
219
- * Filter out any items which are `undefined`.
220
- */
125
+ /** {@inheritDoc iterator.present} */
221
126
  present(): IteratorObject<Present<T>, undefined>;
222
- /**
223
- * Filter out any items which are `null` or `undefined`.
224
- */
127
+ /** {@inheritDoc iterator.nonNullable} */
225
128
  nonNullable(): IteratorObject<NonNullable<T>, undefined>;
226
- /**
227
- * Test whether the given Iterable has the same contents as this
228
- * iterator.
229
- *
230
- * Note that this will consume this iterator up to the point
231
- * where the values diverge. You should not rely on any particular state
232
- * of the iterator afterwards, but consider it spent.
233
- */
129
+ /** {@inheritDoc iterator.equals} */
234
130
  equals<T = unknown, U = unknown>(
235
131
  value: Iterable<U>,
236
- equalsFn?: (a: T, b: U) => boolean
132
+ equalsFn?: (a: T, b: U) => boolean,
237
133
  ): boolean;
238
134
  }
239
135
  }
@@ -241,133 +137,38 @@ declare global {
241
137
  // Object
242
138
 
243
139
  defineProperties(Object, {
244
- get<O extends object, K extends keyof O>(obj: O, key: K): Option<O[K]> {
245
- return Object.hasOwn(obj, key) ? Some(obj[key]) : None;
246
- },
247
-
248
- mapEntries<A, B>(
249
- obj: Record<string, A>,
250
- fn: (entry: [key: string, value: A]) => [string, B]
251
- ): Record<string, B> {
252
- return Object.fromEntries(Object.entries(obj).map(fn));
253
- },
140
+ get: object.get,
141
+ mapEntries: object.mapEntries,
254
142
  });
255
143
 
256
144
  // Map
257
145
 
258
146
  defineProperties(Map.prototype, {
259
- getOrInsertComputed<K, V>(
260
- this: Map<K, NonNullable<V>>,
261
- key: K,
262
- defaultValue: (key: K) => NonNullable<V>
263
- ): V {
264
- const result = this.get(key);
265
- if (result !== undefined) {
266
- return result;
267
- }
268
- const newValue = defaultValue(key);
269
- this.set(key, newValue);
270
- return newValue;
271
- },
272
- remove<K, V>(this: Map<K, V>, key: K): Option<V> {
273
- const result = this.get(key);
274
- return this.delete(key) ? Some(result!) : None;
275
- },
147
+ getOrInsertComputed: map.getOrInsertComputed,
148
+ getOrSet: map.getOrSet,
149
+ remove: map.remove,
276
150
  });
277
151
 
278
152
  // WeakMap
279
153
 
280
154
  defineProperties(WeakMap.prototype, {
281
- getOrInsertComputed<K extends WeakKey, V>(
282
- this: WeakMap<K, NonNullable<V>>,
283
- key: K,
284
- defaultValue: (key: K) => NonNullable<V>
285
- ): V {
286
- const result = this.get(key);
287
- if (result !== undefined) {
288
- return result;
289
- }
290
- const newValue = defaultValue(key);
291
- this.set(key, newValue);
292
- return newValue;
293
- },
294
- remove<K extends WeakKey, V>(this: WeakMap<K, V>, key: K): Option<V> {
295
- const result = this.get(key);
296
- return this.delete(key) ? Some(result!) : None;
297
- },
155
+ getOrInsertComputed: weakmap.getOrInsertComputed,
156
+ getOrSet: weakmap.getOrSet,
157
+ remove: weakmap.remove,
298
158
  });
299
159
 
300
160
  // Array
301
161
 
302
162
  defineProperties(Array.prototype, {
303
- remove<T>(this: Array<T>, value: T): Option<T> {
304
- return this.removeIndex(this.indexOf(value));
305
- },
306
-
307
- removeFn<T>(
308
- this: Array<T>,
309
- predicate: (value: T, index: number, obj: Array<T>) => boolean
310
- ): Option<T> {
311
- return this.removeIndex(this.findIndex(predicate as () => boolean));
312
- },
313
-
314
- removeIndex<T>(this: Array<T>, index: number): Option<T> {
315
- if (!Number.isInteger(index)) {
316
- throw new TypeError(`Array.removeIndex(): index ${index} is not an integer`);
317
- }
318
- if (index < 0 || index >= this.length) {
319
- return None;
320
- }
321
- const removed = this.splice(index, 1).pop();
322
- return Option.from(removed);
323
- },
324
-
325
- insert<T>(this: Array<T>, value: T, index: number): Array<T> {
326
- if (!Number.isInteger(index)) {
327
- throw new TypeError(`Array.insert(): index ${index} is not an integer`);
328
- }
329
- if (index > this.length || index < 0) {
330
- throw new RangeError(`Array.insert: index ${index} out of bounds`);
331
- }
332
- this.splice(index, 0, value);
333
- return this;
334
- },
335
-
336
- insertOrdered<T>(
337
- this: Array<T>,
338
- value: T,
339
- cmp: OrderFn<T>,
340
- duplicates: "low" | "high" = "high"
341
- ): Array<T> {
342
- return this.insert(
343
- value,
344
- (duplicates === "low" ? bisectLow : bisectHigh)(cmp, this, value)
345
- );
346
- },
347
-
348
- present<T>(this: Array<T>): Array<Present<T>> {
349
- return this.filter((value: T): value is Present<T> => value !== undefined);
350
- },
351
-
352
- nonNullable<T>(this: Array<T>): Array<NonNullable<T>> {
353
- return this.filter((value: T): value is NonNullable<T> => value !== undefined);
354
- },
355
-
356
- get<T>(this: Array<T>, index: number): Option<T> {
357
- return Object.get(this, index);
358
- },
359
-
360
- equals<T, U = unknown>(
361
- this: Array<T>,
362
- other: unknown,
363
- equalsFn?: (a: T, b: U) => boolean
364
- ): other is Array<T> {
365
- return (
366
- Array.isArray(other) &&
367
- this.length === other.length &&
368
- Iterator.from(this).equals(other, equalsFn)
369
- );
370
- },
163
+ remove: array.remove,
164
+ removeFn: array.removeFn,
165
+ removeIndex: array.removeIndex,
166
+ insert: array.insert,
167
+ insertOrdered: array.insertOrdered,
168
+ present: array.present,
169
+ nonNullable: array.nonNullable,
170
+ get: array.get,
171
+ equals: array.equals,
371
172
  });
372
173
 
373
174
  shimUnscopables("remove");
@@ -383,136 +184,22 @@ shimUnscopables("equals");
383
184
  // Iterator
384
185
 
385
186
  defineProperties(Iterator, {
386
- empty<T>(): IteratorObject<T> {
387
- return Iterator.from([]);
388
- },
187
+ empty: iterator.empty,
188
+ concat: iterator.concat,
189
+ zip: iterator.zip,
190
+ zipKeyed: iterator.zipKeyed,
389
191
  });
390
192
 
391
193
  defineProperties(Iterator.prototype, {
392
- takeOne<T>(this: Iterator<T>): Option<T> {
393
- const result = this.next();
394
- return result.done === true ? None : Some(result.value);
395
- },
396
-
397
- takeWhile<T>(
398
- this: IteratorObject<T, undefined>,
399
- predicate: (value: T, index: number) => boolean
400
- ): IteratorObject<T, undefined> {
401
- const iter = this;
402
- let index = 0;
403
- let done = false;
404
- return Iterator.from<T>({
405
- next(): IteratorResult<T, undefined> {
406
- if (!done) {
407
- const result = iter.next();
408
- if (result.done === true) {
409
- return result;
410
- }
411
- if (predicate(result.value, index++)) {
412
- return result;
413
- }
414
- }
415
- done = true;
416
- return { done: true, value: undefined };
417
- },
418
- });
419
- },
420
-
421
- skipWhile<T>(
422
- this: IteratorObject<T, undefined>,
423
- predicate: (value: T, index: number) => boolean
424
- ): IteratorObject<T, undefined> {
425
- const iter = this;
426
- let index = 0;
427
- let skipped = false;
428
- return Iterator.from<T>({
429
- next(): IteratorResult<T, undefined> {
430
- if (skipped) {
431
- return iter.next();
432
- }
433
- while (true) {
434
- const result = iter.next();
435
- if (result.done === true) {
436
- return result;
437
- }
438
- if (!predicate(result.value, index++)) {
439
- skipped = true;
440
- return result;
441
- }
442
- }
443
- },
444
- });
445
- },
446
-
447
- findMap<T, U>(
448
- this: IteratorObject<T, undefined>,
449
- mapFn: (value: T, index: number) => NonNullable<U> | undefined
450
- ): NonNullable<U> | undefined {
451
- let index = 0;
452
- while (true) {
453
- const result = this.next();
454
- if (result.done === true) {
455
- return undefined;
456
- }
457
- const mapped = mapFn(result.value, index++);
458
- if (mapped !== undefined) {
459
- return mapped;
460
- }
461
- }
462
- },
463
-
464
- partition<T>(
465
- this: IteratorObject<T, undefined>,
466
- size: number
467
- ): IteratorObject<Array<T>, undefined> {
468
- return this.chunks(size);
469
- },
470
-
471
- frontBiasedPartition<T>(this: IteratorObject<T, undefined>, size: number): Array<Array<T>> {
472
- const input = this.toArray();
473
- let inputPos = 0;
474
- const firstLength = input.length % size;
475
- const output: Array<Array<T>> = [];
476
- if (firstLength > 0) {
477
- output.push(input.slice(0, firstLength));
478
- inputPos = firstLength;
479
- }
480
- while (inputPos < input.length) {
481
- output.push(input.slice(inputPos, inputPos + size));
482
- inputPos += size;
483
- }
484
- assert(inputPos === input.length);
485
- return output;
486
- },
487
-
488
- present<T>(this: IteratorObject<T, undefined>): IteratorObject<Present<T>, undefined> {
489
- return Iterator.from(this.filter((item): item is Present<T> => item !== undefined));
490
- },
491
-
492
- nonNullable<T>(this: IteratorObject<T, undefined>): IteratorObject<NonNullable<T>, undefined> {
493
- return Iterator.from(
494
- this.filter((item): item is NonNullable<T> => item !== undefined && item !== null)
495
- );
496
- },
497
-
498
- equals(
499
- this: IteratorObject<unknown, undefined>,
500
- value: Iterable<unknown>,
501
- equalsFn: (a: unknown, b: unknown) => boolean = Object.is
502
- ): boolean {
503
- const other = Iterator.from(value);
504
- while (true) {
505
- const a = this.next();
506
- const b = other.next();
507
- if (
508
- a.done !== b.done ||
509
- (a.done === false && b.done === false && !equalsFn(a.value, b.value as any))
510
- ) {
511
- return false;
512
- }
513
- if (a.done === true && b.done === true) {
514
- return true;
515
- }
516
- }
517
- },
194
+ chunks: iterator.chunks,
195
+ takeOne: iterator.takeOne,
196
+ takeWhile: iterator.takeWhile,
197
+ skipWhile: iterator.skipWhile,
198
+ findMap: iterator.findMap,
199
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
200
+ partition: iterator.partition,
201
+ frontBiasedPartition: iterator.frontBiasedPartition,
202
+ present: iterator.present,
203
+ nonNullable: iterator.nonNullable,
204
+ equals: iterator.equals,
518
205
  });