@gershy/clearing 0.0.6 → 0.0.7

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/readme.md CHANGED
@@ -10,4 +10,787 @@ search through the dense forest, looking for... a *clearing*.
10
10
 
11
11
  Thanks Bob that's plenty.
12
12
 
13
- The clearing module gives you all the features any sane person would want to see in javascript.
13
+ The clearing module gives you all the features any sane person would want to see in javascript.
14
+
15
+ ## Basic bootstrapping
16
+
17
+ Clearing uses an unorthodox (controversial??) technique to achieve a lot of convenience.
18
+ Functionality is added by extending native classes and prototypes with _non-enumerable_, _Symbol_ properties like so:
19
+
20
+ ```ts
21
+ const coolNewHelper = Symbol();
22
+ Object.defineProperty(Object.prototype, coolNewHelper, { enumerable: false, value: function() {
23
+ return Object.keys(this).map(key => key.toUpperCase());
24
+ }});
25
+
26
+ const obj = { a: 1, b: 2, c: 3 };
27
+ console.log(obj[coolNewHelper]());
28
+ ```
29
+
30
+ Extending native classes and prototypes is kind of crazy, but only doing so with non-enumerable,
31
+ Symbol properties maintains compatibility with the vast majority of npm modules. Oh there's one
32
+ more thing - the symbols used to extend functionality are set in the global scope, so they are
33
+ always globally available.
34
+
35
+ ## `Object` extensions
36
+
37
+ There are currently no extensions on the `Object` class.
38
+
39
+ ## `Object.prototype` extensions
40
+
41
+ ### `Object.prototype[at]`
42
+
43
+ References a potentially nested own property.
44
+
45
+ ```ts
46
+ const obj = { a: { b: { c: 'z' } } };
47
+ console.log(obj[at]([ 'a', 'b', 'c' ])); // "z"
48
+ ```
49
+
50
+ A default value can be supplied if nested lookup finds nothing.
51
+
52
+ ```ts
53
+ const obj = { a: { b: { c: 'z' } } };
54
+ console.log(obj[at]([ 'missing' ], 'default')); // "default"
55
+ console.log(obj[at]([ 'a', 'lol', 'c' ], 'default')); // "default"
56
+ console.log(obj[at]([ 'a', 'b', 'haha' ], 'default')); // "default"
57
+ ```
58
+
59
+ ### `Object.prototype[count]`
60
+
61
+ Returns the number of own properties in an object.
62
+
63
+ ```ts
64
+ console.log({}[count]()); // 0
65
+ console.log({ a: 1, b: 2 }[count]()); // 2
66
+ console.log({ a: 1, b: 2, c: 3 }[count]()); // 3
67
+ ```
68
+
69
+ ### `Object.prototype[empty]`
70
+
71
+ Returns whether an object has any properties.
72
+
73
+ ```ts
74
+ console.log({}[empty]()); // true
75
+ console.log({ a: 1 }[empty]()); // false
76
+ ```
77
+
78
+ ### `Object.prototype[group]`
79
+
80
+ Splits an object into sub-object groups based on a function returning group names.
81
+
82
+ ```ts
83
+ const obj = { a: 1, b: 10, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 2 };
84
+
85
+ console.log(obj[group](n => {
86
+ if (n < 4) return 'small';
87
+ if (n < 8) return 'medium';
88
+ return 'big';
89
+ });
90
+
91
+ /*
92
+ {
93
+ small: { a: 1, c: 3, j: 2 },
94
+ medium: { d: 4, e: 5, f: 6, g: 7 },
95
+ big: { b: 10, h: 8, i: 9 }
96
+ }
97
+ */
98
+ ```
99
+
100
+ ### `Object.prototype[has]`
101
+
102
+ Determines own property existence.
103
+
104
+ ```ts
105
+ const obj = { a: 1, b: 2 };
106
+ console.log(obj[has]('a')); // true
107
+ console.log(obj[has]('b')); // true
108
+ console.log(obj[has]('z')); // false
109
+ ```
110
+
111
+ ### `Object.prototype[map]`
112
+
113
+ Maps over object values, returning a new object. Return `skip` to omit a property.
114
+
115
+ ```ts
116
+ const { skip } = clearing;
117
+ const obj = { a: 1, b: 2, c: 3 };
118
+ console.log(obj[map](v => v * 2)); // { a: 2, b: 4, c: 6 }
119
+ console.log(obj[map](v => v > 1 ? v : skip)); // { b: 2, c: 3 }
120
+ ```
121
+
122
+ ### `Object.prototype[mapk]`
123
+
124
+ Maps over object entries returning `[key, value]` pairs to construct a new object; allows remapping
125
+ keys.
126
+
127
+ ```ts
128
+ const obj = { a: 1, b: 2 };
129
+ console.log(obj[mapk]((v, k) => [ k.toUpperCase(), v * 10 ])); // { A: 10, B: 20 }
130
+ ```
131
+
132
+ ### `Object.prototype[merge]`
133
+
134
+ Deep merges another object into `this` (mutates in place). Use `clearing.skip` for deletion.
135
+
136
+ ```ts
137
+
138
+ const obj = { a: 1, b: { c: 2, d: 3 } };
139
+ obj[merge]({ b: { c: 100 }, e: 4 });
140
+ console.log(obj); // { a: 1, b: { c: 100, d: 3 }, e: 4 }
141
+
142
+ // Deleting properties
143
+ const { skip } = clearing;
144
+ obj[merge]({ a: skip });
145
+ console.log(obj); // { b: { c: 100, d: 3 }, e: 4 }
146
+ ```
147
+
148
+ ### `Object.prototype[slash]`
149
+
150
+ Returns a copy of the object with specified keys removed/omitted.
151
+
152
+ ```ts
153
+ const obj = { a: 1, b: 2, c: 3, d: 4 };
154
+ console.log(obj[slash]([ 'b', 'd' ])); // { a: 1, c: 3 }
155
+ ```
156
+
157
+ ### `Object.prototype[slice]`
158
+
159
+ Returns a copy of the object containing only the specified keys.
160
+
161
+ ```ts
162
+ const obj = { a: 1, b: 2, c: 3, d: 4 };
163
+ console.log(obj[slice]([ 'b', 'd' ])); // { b: 2, d: 4 }
164
+ ```
165
+
166
+ ### `Object.prototype[toArr]`
167
+
168
+ Converts an object to an array by mapping over its entries.
169
+
170
+ ```ts
171
+ const obj = { a: 1, b: 2, c: 3 };
172
+ console.log(obj[toArr]((v, k) => `${k}=${v}`)); // [ 'a=1', 'b=2', 'c=3' ]
173
+ ```
174
+
175
+ ### `Object.prototype[Symbol.iterator]`
176
+
177
+ Makes objects iterable, yielding `[key, value]` pairs.
178
+
179
+ ```ts
180
+ const obj = { a: 1, b: 2 };
181
+ for (const [ k, v ] of obj) console.log(k, v);
182
+ // "a" 1
183
+ // "b" 2
184
+ ```
185
+
186
+ ## `Array` extensions
187
+
188
+ There are currently no extensions on the `Array` class.
189
+
190
+ ## `Array.prototype` extensions
191
+
192
+ ### `Array.prototype[add]`
193
+
194
+ Pushes an item onto the array and returns that item.
195
+
196
+ ```ts
197
+ const arr = [ 1, 2, 3 ];
198
+ const added = arr[add](4);
199
+ console.log(added); // 4
200
+ console.log(arr); // [ 1, 2, 3, 4 ]
201
+ ```
202
+
203
+ ### `Array.prototype[count]`
204
+
205
+ Returns the length of the array.
206
+
207
+ ```ts
208
+ console.log([ 1, 2, 3 ][count]()); // 3
209
+ console.log([][count]()); // 0
210
+ ```
211
+
212
+ ### `Array.prototype[empty]`
213
+
214
+ Returns whether the array has no elements.
215
+
216
+ ```ts
217
+ console.log([][empty]()); // true
218
+ console.log([ 1, 2, 3 ][empty]()); // false
219
+ ```
220
+
221
+ ### `Array.prototype[find]`
222
+
223
+ Finds an element matching a predicate, returning `{ found, val, ind }`.
224
+
225
+ ```ts
226
+ const arr = [ 10, 20, 30, 40 ];
227
+
228
+ const result = arr[find](v => v > 25);
229
+ console.log(result); // { found: true, val: 30, ind: 2 }
230
+
231
+ const missing = arr[find](v => v > 100);
232
+ console.log(missing); // { found: false, val: null, ind: null }
233
+ ```
234
+
235
+ ### `Array.prototype[group]`
236
+
237
+ Splits an array into sub-arrays based on a function returning group names.
238
+
239
+ ```ts
240
+ const arr = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
241
+
242
+ console.log(arr[group](n => {
243
+ if (n < 4) return 'small';
244
+ if (n < 8) return 'medium';
245
+ return 'big';
246
+ }));
247
+
248
+ /*
249
+ {
250
+ small: [ 1, 2, 3 ],
251
+ medium: [ 4, 5, 6, 7 ],
252
+ big: [ 8, 9, 10 ]
253
+ }
254
+ */
255
+ ```
256
+
257
+ ### `Array.prototype[has]`
258
+
259
+ Checks if an array includes a value.
260
+
261
+ ```ts
262
+ console.log([ 1, 2, 3 ][has](2)); // true
263
+ console.log([ 1, 2, 3 ][has](5)); // false
264
+ ```
265
+
266
+ ### `Array.prototype[map]`
267
+
268
+ Maps over array values. Return `clearing.skip` to omit an element (filter + map in one).
269
+
270
+ ```ts
271
+ const arr = [ 1, 2, 3, 4, 5 ];
272
+ console.log(arr[map](v => v * 2)); // [ 2, 4, 6, 8, 10 ]
273
+
274
+ const { skip } = clearing;
275
+ console.log(arr[map](v => v > 2 ? v * 10 : skip)); // [ 30, 40, 50 ]
276
+ ```
277
+
278
+ ### `Array.prototype[rem]`
279
+
280
+ Removes the first occurrence of a value from the array (mutates in place).
281
+
282
+ ```ts
283
+ const arr = [ 1, 2, 3, 2, 4 ];
284
+ arr[rem](2);
285
+ console.log(arr); // [ 1, 3, 2, 4 ]
286
+ ```
287
+
288
+ ### `Array.prototype[toObj]`
289
+
290
+ Converts an array to an object by mapping each element to a `[key, value]` pair.
291
+
292
+ ```ts
293
+ const arr = [ 'a', 'b', 'c' ];
294
+ console.log(arr[toObj]((v, i) => [ v, i ])); // { a: 0, b: 1, c: 2 }
295
+ ```
296
+
297
+ ## `String` extensions
298
+
299
+ ### `String[baseline]`
300
+
301
+ Allows writing coherent multiline strings with predictable indentation.
302
+
303
+ ```ts
304
+ const text = (() => {
305
+
306
+ return (() => {
307
+
308
+ return (() => {
309
+
310
+ return String[baseline](`
311
+ | Even though this text is in an indented scope, it will have predictable indentation.
312
+ |
313
+ | This is achieved by using the pipe ("|") character plus a space as a delimiter for
314
+ | every line.
315
+ |
316
+ | You can also pass a 2nd argument to String[baseline] to change the delimiter.
317
+ |
318
+ | Thanks for your attention :)
319
+ `);
320
+
321
+ })();
322
+
323
+ })();
324
+
325
+ })();
326
+ ```
327
+
328
+ ### `String[base32]`, `String[base36]`, `String[base62]`, `String[base64Url]`, `String[base64Std]`
329
+
330
+ Character sets for encoding/decoding numbers to strings.
331
+
332
+ ```ts
333
+ console.log(String[base32]); // '0123456789abcdefghijklmnopqrstuv'
334
+ console.log(String[base36]); // '0123456789abcdefghijklmnopqrstuvwxyz'
335
+ console.log(String[base62]); // '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
336
+ console.log(String[base64Url]); // '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_'
337
+ console.log(String[base64Std]); // '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'
338
+ ```
339
+
340
+ ## `String.prototype` extensions
341
+
342
+ ### `String.prototype[code]`
343
+
344
+ Returns the character code at a given index (default 0).
345
+
346
+ ```ts
347
+ console.log('A'[code]()); // 65
348
+ console.log('AB'[code](1)); // 66
349
+ ```
350
+
351
+ ### `String.prototype[count]`
352
+
353
+ Returns the length of the string.
354
+
355
+ ```ts
356
+ console.log('hello'[count]()); // 5
357
+ console.log(''[count]()); // 0
358
+ ```
359
+
360
+ ### `String.prototype[cut]`
361
+
362
+ Splits a string by a delimiter with a maximum number of cuts.
363
+
364
+ ```ts
365
+ console.log('a:b:c:d:e'[cut](':')); // [ 'a', 'b:c:d:e' ]
366
+ console.log('a:b:c:d:e'[cut](':', 2)); // [ 'a', 'b', 'c:d:e' ]
367
+ console.log('a:b:c:d:e'[cut](':', Infinity)); // [ 'a', 'b', 'c', 'd', 'e' ]
368
+ ```
369
+
370
+ ### `String.prototype[has]`
371
+
372
+ Checks if a string contains a substring.
373
+
374
+ ```ts
375
+ console.log('hello world'[has]('world')); // true
376
+ console.log('hello world'[has]('xyz')); // false
377
+ ```
378
+
379
+ ### `String.prototype[hasHead]`
380
+
381
+ Checks if a string starts with a given prefix.
382
+
383
+ ```ts
384
+ console.log('hello world'[hasHead]('hello')); // true
385
+ console.log('hello world'[hasHead]('world')); // false
386
+ ```
387
+
388
+ ### `String.prototype[hasTail]`
389
+
390
+ Checks if a string ends with a given suffix.
391
+
392
+ ```ts
393
+ console.log('hello world'[hasTail]('world')); // true
394
+ console.log('hello world'[hasTail]('hello')); // false
395
+ ```
396
+
397
+ ### `String.prototype[indent]`
398
+
399
+ Indents each line of a string.
400
+
401
+ ```ts
402
+ const text = 'line1\nline2\nline3';
403
+
404
+ console.log(text[indent]()); // 2 spaces (default)
405
+ console.log(text[indent](4)); // 4 spaces
406
+ console.log(text[indent](2, '-')); // '--' prefix
407
+ console.log(text[indent]('>>> ')); // custom prefix
408
+ ```
409
+
410
+ ### `String.prototype[lower]`
411
+
412
+ Converts the string to lowercase.
413
+
414
+ ```ts
415
+ console.log('HELLO'[lower]()); // 'hello'
416
+ ```
417
+
418
+ ### `String.prototype[upper]`
419
+
420
+ Converts the string to uppercase.
421
+
422
+ ```ts
423
+ console.log('hello'[upper]()); // 'HELLO'
424
+ ```
425
+
426
+ ### `String.prototype[padHead]`
427
+
428
+ Pads the start of the string to a given length.
429
+
430
+ ```ts
431
+ console.log('5'[padHead](3, '0')); // '005'
432
+ ```
433
+
434
+ ### `String.prototype[padTail]`
435
+
436
+ Pads the end of the string to a given length.
437
+
438
+ ```ts
439
+ console.log('5'[padTail](3, '0')); // '500'
440
+ ```
441
+
442
+ ### `String.prototype[toNum]`
443
+
444
+ Decodes a string to a BigInt using a given charset.
445
+
446
+ ```ts
447
+ console.log('ff'[toNum](String[charset]('0123456789abcdef'))); // 255n
448
+ console.log('10'[toNum](String[base62])); // 62n
449
+ ```
450
+
451
+ ## `Number` extensions
452
+
453
+ ### `Number[int32]`, `Number[int64]`
454
+
455
+ Constants for 32-bit and 64-bit integer ranges.
456
+
457
+ ```ts
458
+ console.log(Number[int32]); // 4294967296 (2^32)
459
+ console.log(Number[int64]); // 18446744073709551616 (2^64)
460
+ ```
461
+
462
+ ## `Number.prototype` extensions
463
+
464
+ ### `Number.prototype[char]`
465
+
466
+ Converts a character code to its character.
467
+
468
+ ```ts
469
+ console.log((65)[char]()); // 'A'
470
+ console.log((97)[char]()); // 'a'
471
+ ```
472
+
473
+ ### `Number.prototype[isInt]`
474
+
475
+ Returns whether a number is an integer.
476
+
477
+ ```ts
478
+ console.log((5)[isInt]()); // true
479
+ console.log((5.1)[isInt]()); // false
480
+ ```
481
+
482
+ ### `Number.prototype[toArr]`
483
+
484
+ Creates an array of length `n` by mapping over indices.
485
+
486
+ ```ts
487
+ console.log((5)[toArr](i => i * 2)); // [ 0, 2, 4, 6, 8 ]
488
+ ```
489
+
490
+ ### `Number.prototype[toObj]`
491
+
492
+ Creates an object by mapping over indices, returning `[key, value]` pairs.
493
+
494
+ ```ts
495
+ console.log((3)[toObj](i => [ `key${i}`, i * 10 ])); // { key0: 0, key1: 10, key2: 20 }
496
+ ```
497
+
498
+ ### `Number.prototype[toStr]`
499
+
500
+ Encodes a number to a string using a given charset.
501
+
502
+ ```ts
503
+ console.log((255)[toStr](String[charset]('0123456789abcdef'))); // 'ff'
504
+ console.log((62)[toStr](String[base62])); // '10'
505
+ console.log((5)[toStr](String[base62], 4)); // '0005' (padded)
506
+ ```
507
+
508
+ ### `Number.prototype[Symbol.iterator]`
509
+
510
+ Makes numbers iterable from 0 to n-1.
511
+
512
+ ```ts
513
+ for (const i of 3) console.log(i);
514
+ // 0
515
+ // 1
516
+ // 2
517
+
518
+ console.log([ ...5 ]); // [ 0, 1, 2, 3, 4 ]
519
+ ```
520
+
521
+ ### `Number.prototype[bits]`
522
+
523
+ Yields the bits of a number (least significant first).
524
+
525
+ ```ts
526
+ console.log([ ...(13)[bits]() ]); // [ 1, 0, 1, 1 ] (13 is 1101 in binary)
527
+ ```
528
+
529
+ ## `BigInt.prototype` extensions
530
+
531
+ ### `BigInt.prototype[toStr]`
532
+
533
+ Same as `Number.prototype[toStr]`, but for BigInt values.
534
+
535
+ ```ts
536
+ console.log((1000000000000n)[toStr](String[base62])); // 'bLY38W'
537
+ ```
538
+
539
+ ## `Function.prototype` extensions
540
+
541
+ ### `Function.prototype[bind]`
542
+
543
+ Partially applies arguments to a function (like `bind`, but without a `this` context).
544
+
545
+ ```ts
546
+ const add = (a, b, c) => a + b + c;
547
+ const add10 = add[bind](10);
548
+ console.log(add10(5, 3)); // 18
549
+ ```
550
+
551
+ ## `Error` extensions
552
+
553
+ ### `Error[assert]`
554
+
555
+ Throws an error if the assertion function returns false.
556
+
557
+ ```ts
558
+ Error[assert]({ x: 5, y: 10 }, ({ x, y }) => x < y); // passes
559
+ Error[assert]({ x: 10, y: 5 }, ({ x, y }) => x < y); // throws!
560
+ ```
561
+
562
+ ## `Error.prototype` extensions
563
+
564
+ ### `Error.prototype[mod]`
565
+
566
+ Modifies an error's message and adds properties. Returns the error for chaining.
567
+
568
+ ```ts
569
+ throw Error('something failed')[mod]({ code: 'err99', context: { userId: 123 } });
570
+
571
+ // Can also modify the message
572
+ throw Error('base error')[mod]({ message: 'enhanced message', extra: 'data' });
573
+ ```
574
+
575
+ ### `Error.prototype[fire]`
576
+
577
+ Shorthand for `throw error[mod](props)`.
578
+
579
+ ```ts
580
+ Error('something failed')[fire]({ code: 'err99' });
581
+ ```
582
+
583
+ ### `Error.prototype[limn]`
584
+
585
+ Converts an error (and its cause chain) to a plain, json-serializable object.
586
+
587
+ ```ts
588
+ const err = Error('outer')[mod]({ cause: Error('inner') });
589
+ console.log(err[limn]());
590
+ /*
591
+ {
592
+ form: 'Error',
593
+ msg: 'outer',
594
+ trace: [ ... ],
595
+ cause: { form: 'Error', msg: 'inner', trace: [ ... ], cause: null }
596
+ }
597
+ */
598
+ ```
599
+
600
+ ### `Error.prototype[suppress]`
601
+
602
+ Marks an error (and its causes) as suppressed for custom error handling.
603
+
604
+ ```ts
605
+ const err = Error('handled gracefully');
606
+ err[suppress]();
607
+ console.log(err[Symbol.for('clearing.err.suppressed')]); // true
608
+ ```
609
+
610
+ Useful for preventing certain errors from crashing the js process, for example in node.js:
611
+ ```ts
612
+ process.on('unhandledException', err => {
613
+
614
+ // Ignore suppressed errors
615
+ if (err[Symbol.for('clearing.err.suppressed')]) return;
616
+
617
+ console.log('Fatal error!');
618
+ process.exit(1);
619
+
620
+ });
621
+ ```
622
+
623
+ ## `Promise` extensions
624
+
625
+ ### `Promise[allArr]`
626
+
627
+ Alias for `Promise.all`.
628
+
629
+ ```ts
630
+ const results = await Promise[allArr]([ fetch('/a'), fetch('/b'), fetch('/c') ]);
631
+ ```
632
+
633
+ ### `Promise[allObj]`
634
+
635
+ Like `Promise.all`, but for an object of promises, returning an object of results.
636
+
637
+ ```ts
638
+ const results = await Promise[allObj]({
639
+ user: fetchUser(),
640
+ posts: fetchPosts(),
641
+ comments: fetchComments()
642
+ });
643
+ console.log(results.user, results.posts, results.comments);
644
+ ```
645
+
646
+ ### `Promise[later]`
647
+
648
+ Creates a promise with externally accessible `resolve` and `reject` functions.
649
+
650
+ ```ts
651
+ const p = Promise[later]();
652
+
653
+ setTimeout(() => p.resolve('done!'), 1000);
654
+
655
+ console.log(await p); // 'done!'
656
+ ```
657
+
658
+ ## `Set.prototype` extensions
659
+
660
+ ### `Set.prototype[count]`
661
+
662
+ Returns the size of the set.
663
+
664
+ ```ts
665
+ console.log(new Set([ 1, 2, 3 ])[count]()); // 3
666
+ ```
667
+
668
+ ### `Set.prototype[empty]`
669
+
670
+ Returns whether the set is empty.
671
+
672
+ ```ts
673
+ console.log(new Set()[empty]()); // true
674
+ console.log(new Set([ 1 ])[empty]()); // false
675
+ ```
676
+
677
+ ### `Set.prototype[find]`
678
+
679
+ Finds an element matching a predicate, returning `{ found, val }`.
680
+
681
+ ```ts
682
+ const s = new Set([ 10, 20, 30 ]);
683
+ console.log(s[find](v => v > 15)); // { found: true, val: 20 }
684
+ ```
685
+
686
+ ### `Set.prototype[map]`
687
+
688
+ Maps over set values to produce an array.
689
+
690
+ ```ts
691
+ const s = new Set([ 1, 2, 3 ]);
692
+ console.log(s[map](v => v * 2)); // [ 2, 4, 6 ]
693
+ ```
694
+
695
+ ### `Set.prototype[rem]`
696
+
697
+ Removes a value from the set.
698
+
699
+ ```ts
700
+ const s = new Set([ 1, 2, 3 ]);
701
+ s[rem](2);
702
+ console.log([ ...s ]); // [ 1, 3 ]
703
+ ```
704
+
705
+ ### `Set.prototype[toArr]`
706
+
707
+ Converts a set to an array by mapping over its values.
708
+
709
+ ```ts
710
+ const s = new Set([ 1, 2, 3 ]);
711
+ console.log(s[toArr](v => v * 10)); // [ 10, 20, 30 ]
712
+ ```
713
+
714
+ ### `Set.prototype[toObj]`
715
+
716
+ Converts a set to an object by mapping each value to a `[key, value]` pair.
717
+
718
+ ```ts
719
+ const s = new Set([ 'a', 'b', 'c' ]);
720
+ console.log(s[toObj](v => [ v, v.toUpperCase() ])); // { a: 'A', b: 'B', c: 'C' }
721
+ ```
722
+
723
+ ## `Map.prototype` extensions
724
+
725
+ ### `Map.prototype[add]`
726
+
727
+ Alias for `Map.prototype.set` (for consistency with Set).
728
+
729
+ ```ts
730
+ const m = new Map();
731
+ m[add]('key', 'value');
732
+ ```
733
+
734
+ ### `Map.prototype[count]`
735
+
736
+ Returns the size of the map.
737
+
738
+ ```ts
739
+ const m = new Map([ [ 'a', 1 ], [ 'b', 2 ] ]);
740
+ console.log(m[count]()); // 2
741
+ ```
742
+
743
+ ### `Map.prototype[empty]`
744
+
745
+ Returns whether the map is empty.
746
+
747
+ ```ts
748
+ console.log(new Map()[empty]()); // true
749
+ console.log(new Map([ [ 'a', 1 ] ])[empty]()); // false
750
+ ```
751
+
752
+ ### `Map.prototype[find]`
753
+
754
+ Finds an entry matching a predicate, returning `{ found, val, key }`.
755
+
756
+ ```ts
757
+ const m = new Map([ [ 'a', 10 ], [ 'b', 20 ], [ 'c', 30 ] ]);
758
+ console.log(m[find](v => v > 15)); // { found: true, val: 20, key: 'b' }
759
+ ```
760
+
761
+ ### `Map.prototype[map]`
762
+
763
+ Maps entries to produce an object; iterator receives `(val, key)` and returns `[key, val]`.
764
+
765
+ ```ts
766
+ const m = new Map([ [ 'a', 1 ], [ 'b', 2 ] ]);
767
+ console.log(m[map]((v, k) => [ k.toUpperCase(), v * 10 ])); // { A: 10, B: 20 }
768
+ ```
769
+
770
+ ### `Map.prototype[rem]`
771
+
772
+ Removes an entry from the map by key.
773
+
774
+ ```ts
775
+ const m = new Map([ [ 'a', 1 ], [ 'b', 2 ] ]);
776
+ m[rem]('a');
777
+ console.log(m[count]()); // 1
778
+ ```
779
+
780
+ ### `Map.prototype[toArr]`
781
+
782
+ Converts a map to an array by mapping over its entries.
783
+
784
+ ```ts
785
+ const m = new Map([ [ 'a', 1 ], [ 'b', 2 ] ]);
786
+ console.log(m[toArr]((v, k) => `${k}=${v}`)); // [ 'a=1', 'b=2' ]
787
+ ```
788
+
789
+ ### `Map.prototype[toObj]`
790
+
791
+ Converts a map to an object by mapping over its entries.
792
+
793
+ ```ts
794
+ const m = new Map([ [ 'a', 1 ], [ 'b', 2 ] ]);
795
+ console.log(m[toObj]((v, k) => [ k, v * 100 ])); // { a: 100, b: 200 }
796
+ ```