@rimbu/common 2.0.4 → 2.0.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/dist/bun/eq.mts DELETED
@@ -1,427 +0,0 @@
1
- /**
2
- * A function returning true if given `v1` and `v2` should be considered equal.
3
- */
4
- export type Eq<T> = (v1: T, v2: T) => boolean;
5
-
6
- export namespace Eq {
7
- /**
8
- * Converts any given `value` to a string representation that is stable for equality
9
- * and ordering comparisons.
10
- *
11
- * For primitive values and objects with a custom `toString` implementation, it uses
12
- * `String(value)`. For plain objects with the default `Object.prototype.toString`
13
- * implementation, it uses `JSON.stringify(value)` instead.
14
- * @param value - the value to convert
15
- */
16
- export function convertAnyToString(value: any): string {
17
- if (
18
- typeof value !== 'object' ||
19
- null === value ||
20
- !('toString' in value) ||
21
- typeof value.toString !== 'function' ||
22
- value.toString !== Object.prototype.toString
23
- ) {
24
- return String(value);
25
- }
26
-
27
- return JSON.stringify(value);
28
- }
29
-
30
- const _anyFlatEq: Eq<any> = createAnyEq('FLAT');
31
- const _anyShallowEq: Eq<any> = createAnyEq('SHALLOW');
32
- const _anyDeepEq: Eq<any> = createAnyEq('DEEP');
33
-
34
- /**
35
- * Returns the default Eq instance, which is the Eq.anyDeepEq() instance.
36
- */
37
- export function defaultEq(): Eq<any> {
38
- return _anyDeepEq;
39
- }
40
-
41
- /**
42
- * An Eq instance that uses `Object.is` to determine if two objects are equal.
43
- * @example
44
- * ```ts
45
- * const eq = Eq.objectIs
46
- * console.log(eq(5, 5))
47
- * // => true
48
- * console.log(eq(5, 'a'))
49
- * // => false
50
- * ```
51
- */
52
- export const objectIs: Eq<any> = Object.is;
53
-
54
- const _valueOfEq: Eq<{ valueOf(): any }> = (v1, v2) =>
55
- Object.is(v1.valueOf(), v2.valueOf());
56
-
57
- /**
58
- * Returns an Eq instance for objects that have a `valueOf` method. It returns true if the `.valueOf` values of both given objects are equal.
59
- * @typeparam T - the object type containing a valueOf function of type V
60
- * @typeparam V - the valueOf result type
61
- * @example
62
- * ```ts
63
- * const eq = Eq.valueOfEq()
64
- * console.log(eq(new Number(5), new Number(5)))
65
- * // => true
66
- * console.log(eq(new Number(5), new Number(3)))
67
- * // => false
68
- * ```
69
- */
70
- export function valueOfEq<T extends { valueOf(): V }, V>(): Eq<T> {
71
- return _valueOfEq;
72
- }
73
-
74
- /**
75
- * Returns an Eq instance that compares Date objects according to their `valueOf` value.
76
- * @example
77
- * ```ts
78
- * const eq = Eq.dateEq()
79
- * console.log(eq(new Date(2020, 1, 1), new Date(2020, 1, 1))
80
- * // => true
81
- * console.log(eq(new Date(2020, 1, 1), new Date(2020, 2, 1))
82
- * // => false
83
- * ```
84
- */
85
- export function dateEq(): Eq<Date> {
86
- return _valueOfEq;
87
- }
88
-
89
- function createIterableEq<T>(itemEq: Eq<T>): Eq<Iterable<T>> {
90
- return (v1, v2) => {
91
- if (Object.is(v1, v2)) return true;
92
-
93
- const iter1 = v1[Symbol.iterator]();
94
- const iter2 = v2[Symbol.iterator]();
95
-
96
- while (true) {
97
- const value1 = iter1.next();
98
- const value2 = iter2.next();
99
-
100
- if (value1.done || value2.done) return value1.done === value2.done;
101
-
102
- if (!itemEq(value1.value, value2.value)) return false;
103
- }
104
- };
105
- }
106
-
107
- const _iterableAnyEq: Eq<Iterable<any>> = createIterableEq(defaultEq());
108
-
109
- /**
110
- * Returns an Eq instance that compares Iterables by comparing their elements with the given `itemEq` Eq instance.
111
- * @typeparam T - the Iterable element type
112
- * @param itemEq - (optional) the Eq instance to use to compare the Iterable's elements
113
- * @example
114
- * ```ts
115
- * const eq = Eq.iterableEq();
116
- * console.log(eq([1, 2, 3], [1, 2, 3])
117
- * // => true
118
- * console.log(eq([1, 2, 3], [1, 3, 2])
119
- * // => false
120
- * ```
121
- */
122
- export function iterableEq<T>(itemEq?: Eq<T>): Eq<Iterable<T>> {
123
- if (undefined === itemEq) return _iterableAnyEq;
124
-
125
- return createIterableEq(itemEq);
126
- }
127
-
128
- function createObjectEq(valueEq: Eq<any>): Eq<Record<any, any>> {
129
- return (v1, v2) => {
130
- if (Object.is(v1, v2)) return true;
131
-
132
- if (v1.constructor !== v2.constructor) return false;
133
-
134
- for (const key in v1) {
135
- if (!(key in v2)) return false;
136
- }
137
-
138
- for (const key in v2) {
139
- if (!(key in v1)) return false;
140
- }
141
-
142
- for (const key in v1) {
143
- const value1 = v1[key];
144
- const value2 = v2[key];
145
-
146
- if (!valueEq(value1, value2)) return false;
147
- }
148
-
149
- return true;
150
- };
151
- }
152
-
153
- const _objectEq: Eq<Record<any, any>> = createObjectEq(defaultEq());
154
-
155
- /**
156
- * Returns an Eq instance that checks equality of objects containing property values of type V by iteratively
157
- * applying given `valueEq` to each of the object's property values.
158
- * @typeparam V - the object property value type
159
- * @param valueEq - (optional) the Eq instance to use to compare property values
160
- * @example
161
- * ```ts
162
- * const eq = Eq.objectEq()
163
- * console.log(eq({ a: 1, b: { c: 2 }}, { b: { c: 2 }, a: 1 }))
164
- * // => true
165
- * console.log(eq({ a: 1, b: { c: 2 }}, { a: 1, b: { c: 3 }}))
166
- * // => false
167
- * ```
168
- */
169
- export function objectEq<V = any>(valueEq?: Eq<V>): Eq<Record<any, V>> {
170
- if (undefined === valueEq) return _objectEq;
171
-
172
- return createObjectEq(valueEq);
173
- }
174
-
175
- function createAnyEq(mode: 'FLAT' | 'SHALLOW' | 'DEEP'): Eq<any> {
176
- const result: Eq<any> = (v1, v2): boolean => {
177
- if (Object.is(v1, v2)) return true;
178
-
179
- const type1 = typeof v1;
180
- const type2 = typeof v2;
181
-
182
- if (type1 !== type2) return false;
183
-
184
- switch (type1) {
185
- case 'undefined':
186
- case 'bigint':
187
- case 'boolean':
188
- case 'number':
189
- case 'string':
190
- case 'symbol':
191
- case 'function':
192
- return Object.is(v1, v2);
193
- case 'object': {
194
- if (v1 === null || v2 === null) return false;
195
-
196
- if (v1.constructor !== v2.constructor) {
197
- return false;
198
- }
199
-
200
- if (
201
- v1 instanceof Boolean ||
202
- v1 instanceof Date ||
203
- v1 instanceof Number ||
204
- v1 instanceof String
205
- ) {
206
- return _valueOfEq(v1, v2);
207
- }
208
-
209
- if (mode !== 'FLAT') {
210
- if (Symbol.iterator in v1 && Symbol.iterator in v2) {
211
- if (mode === 'SHALLOW') {
212
- return createIterableEq(_anyFlatEq)(v1, v2);
213
- }
214
-
215
- return createIterableEq(result)(v1, v2);
216
- }
217
-
218
- if (mode === 'SHALLOW') {
219
- return createObjectEq(_anyFlatEq)(v1, v2);
220
- }
221
-
222
- return _objectEq(v1, v2);
223
- }
224
-
225
- // cannot establish that they are equal in flat mode
226
- return false;
227
- }
228
- }
229
- };
230
-
231
- return result;
232
- }
233
-
234
- /**
235
- * Returns an Eq instance that checks equality of any values. For composed values (objects and iterables)
236
- * it will compare with Object.is.
237
- * @typeparam T - the value type
238
- * @example
239
- * ```ts
240
- * const eq = Eq.anyFlatEq()
241
- * console.log(eq(1, 'a'))
242
- * // => false
243
- * console.log(eq({ a: 1, b: 2 }, { b: 2, a: 1 }))
244
- * // => false
245
- * ```
246
- */
247
- export function anyFlatEq<T = any>(): Eq<T> {
248
- return _anyFlatEq;
249
- }
250
-
251
- /**
252
- * Returns an Eq instance that checks equality of any values. For composed values (objects and iterables)
253
- * it will enter 1 level, and if again compound values are found, they are compared
254
- * with Object.is.
255
- * @typeparam T - the value type
256
- * @example
257
- * ```ts
258
- * const eq = Eq.anyShallowEq()
259
- * console.log(eq(1, 'a'))
260
- * // => false
261
- * console.log(eq({ a: 1, b: 2 }, { b: 2, a: 1 }))
262
- * // => true
263
- * console.log(eq([{ a: 1, b: 2 }], [{ b: 2, a: 1 }]))
264
- * // => false
265
- * ```
266
- */
267
- export function anyShallowEq<T = any>(): Eq<T> {
268
- return _anyShallowEq;
269
- }
270
-
271
- /**
272
- * Returns an Eq instance that checks equality of any values. For composed values (objects and iterables)
273
- * it will recursively compare the contained values.
274
- * @note may have poor performance for deeply nested types and large arrays, and objects with circular structures
275
- * may cause infinite loops
276
- * @typeparam T - the value type
277
- * @example
278
- * ```ts
279
- * const eq = Eq.anyDeepEq()
280
- * console.log(eq(1, 'a'))
281
- * // => false
282
- * console.log(eq({ a: 1, b: 2 }, { b: 2, a: 1 }))
283
- * // => true
284
- * console.log(eq([{ a: 1, b: 2 }], [{ b: 2, a: 1 }]))
285
- * // => false
286
- * ```
287
- */
288
- export function anyDeepEq<T = any>(): Eq<T> {
289
- return _anyDeepEq;
290
- }
291
-
292
- const _defaultCollator = Intl.Collator('und');
293
-
294
- const _defaultStringCollatorEq: Eq<any> = (v1, v2) =>
295
- _defaultCollator.compare(v1, v2) === 0;
296
-
297
- /**
298
- * Returns an Eq instance that considers strings equal taking the given or default locale into account.
299
- * @param locales - (optional) a locale or list of locales
300
- * @param options - (optional) see String.localeCompare for details
301
- * @example
302
- * ```ts
303
- * const eq = Eq.createStringCollatorEq()
304
- * console.log(eq('a', 'a'))
305
- * // => true
306
- * console.log(eq('abc', 'aBc'))
307
- * // => false
308
- * ```
309
- */
310
- export function createStringCollatorEq(
311
- ...args: ConstructorParameters<typeof Intl.Collator>
312
- ): Eq<string> {
313
- if (args.length === 0) return _defaultStringCollatorEq;
314
-
315
- const collator = Intl.Collator(...args);
316
-
317
- return (v1, v2) => collator.compare(v1, v2) === 0;
318
- }
319
-
320
- const _stringCaseInsensitiveEq: Eq<string> = createStringCollatorEq('und', {
321
- sensitivity: 'accent',
322
- });
323
-
324
- /**
325
- * Returns an Eq instance that considers strings equal regardless of their case.
326
- * @example
327
- * ```ts
328
- * const eq = Eq.stringCaseInsentitiveEq()
329
- * console.log(eq('aB', 'Ab'))
330
- * // => true
331
- * console.log(eq('aBc', 'abB'))
332
- * // => false
333
- * ```
334
- */
335
- export function stringCaseInsentitiveEq(): Eq<string> {
336
- return _stringCaseInsensitiveEq;
337
- }
338
-
339
- const _stringCharCodeEq: Eq<string> = (v1, v2) => {
340
- const len = v1.length;
341
-
342
- if (len !== v2.length) return false;
343
-
344
- let i = -1;
345
-
346
- while (++i < len) {
347
- if (v1.charCodeAt(i) !== v2.charCodeAt(i)) return false;
348
- }
349
-
350
- return true;
351
- };
352
-
353
- /**
354
- * Returns an Eq instance that considers strings equal when all their charcodes are equal.
355
- * @example
356
- * ```ts
357
- * const eq = Eq.stringCharCodeEq()
358
- * console.log(eq('a', 'a'))
359
- * // => true
360
- * console.log(eq('abc', 'aBc'))
361
- * // => false
362
- * ```
363
- */
364
- export function stringCharCodeEq(): Eq<string> {
365
- return _stringCharCodeEq;
366
- }
367
-
368
- const _anyToStringEq: Eq<any> = (v1, v2) =>
369
- convertAnyToString(v1) === convertAnyToString(v2);
370
-
371
- /**
372
- * Returns an Eq instance that considers two values equal when their string
373
- * representations, as returned by `Eq.convertAnyToString`, are equal.
374
- * @example
375
- * ```ts
376
- * const eq = Eq.anyToStringEq()
377
- * console.log(eq({ a: 1 }, { a: 1 }))
378
- * // => true
379
- * console.log(eq({ a: 1 }, { a: 2 }))
380
- * // => false
381
- * ```
382
- */
383
- export function anyToStringEq(): Eq<any> {
384
- return _anyToStringEq;
385
- }
386
-
387
- const _anyJsonEq: Eq<any> = (v1, v2) =>
388
- JSON.stringify(v1) === JSON.stringify(v2);
389
-
390
- /**
391
- * Returns an Eq instance that considers values equal their JSON.stringify values are equal.
392
- * @example
393
- * ```ts
394
- * const eq = Eq.anyJsonEq()
395
- * console.log(eq({ a: 1, b: 2 }, { a: 1, b: 2 }))
396
- * // => true
397
- * console.log(eq({ a: 1, b: 2 }, { b: 2, a: 1 }))
398
- * // => false
399
- * ```
400
- */
401
- export function anyJsonEq(): Eq<any> {
402
- return _anyJsonEq;
403
- }
404
-
405
- /**
406
- * Returns an `Eq` instance for tuples that considers two tuples [A, B] and [C, D] equal if [A, B] equals [C, D],
407
- * or if [A, B] equals [D, C]
408
- * @param eq - (optional) an alternative `Eq` instance to use for the values in the tuple
409
- * @example
410
- * ```ts
411
- * const eq = Eq.tupleSymmetric()
412
- * console.log(eq([1, 2], [1, 2]))
413
- * // => true
414
- * console.log(eq([1, 2], [2, 1]))
415
- * // => true
416
- * console.log(eq([1, 3], [2, 1]))
417
- * // => false
418
- * ```
419
- */
420
- export function tupleSymmetric<T>(
421
- eq: Eq<T> = defaultEq()
422
- ): Eq<readonly [T, T]> {
423
- return (tup1: readonly [T, T], tup2: readonly [T, T]): boolean =>
424
- (eq(tup1[0], tup2[0]) && eq(tup1[1], tup2[1])) ||
425
- (eq(tup1[0], tup2[1]) && eq(tup1[1], tup2[0]));
426
- }
427
- }
package/dist/bun/err.mts DELETED
@@ -1,46 +0,0 @@
1
- /**
2
- * Throws an `ErrBase.ForcedError` error when called.
3
- * @example
4
- * ```ts
5
- * const emptyMap = HashMap.empty<number, string>()
6
- * emptyMap.get(5, Err);
7
- * // throws: ErrBase.ForcedError(message: 'Err: Forced to throw error')
8
- * ```
9
- */
10
- export function Err(): never {
11
- return ErrBase.msg('Err: Forced to throw error')();
12
- }
13
-
14
- export namespace ErrBase {
15
- /**
16
- * A custom error instance.
17
- */
18
- export abstract class CustomError {
19
- constructor(readonly message: string) {}
20
-
21
- get name(): string {
22
- return this.constructor.name;
23
- }
24
- }
25
-
26
- /**
27
- * Error type that is thrown by `Err` and the functions returned by `ErrBase.msg`.
28
- */
29
- export class ForcedError extends CustomError {}
30
-
31
- /**
32
- * Returns a function that, when called, throws an `Err.ForcedError` with the given `message` string.
33
- * @param message - the message to put in the `Err.ForcedError` instance.
34
- * @example
35
- * ```ts
36
- * const emptyMap = HashMap.empty<number, string>()
37
- * emptyMap.get(5, ErrBase.msg('not found'));
38
- * // throws: ErrBase.ForcedError(message: 'not found')
39
- * ```
40
- */
41
- export function msg(message: string): () => never {
42
- return function (): never {
43
- throw new ErrBase.ForcedError(message);
44
- };
45
- }
46
- }
@@ -1,120 +0,0 @@
1
- import type { Range } from './internal.mts';
2
-
3
- /**
4
- * A flexible range specification for numeric indices.
5
- * If a start or end is defined, a tuple can be used where the second item is a boolean
6
- * indicating whether that end is inclusive or exclusive.<br/>
7
- * An IndexRange can have one of the following forms:<br/>
8
- * <br/>
9
- * - { amount: number }<br/>
10
- * - { start: number }<br/>
11
- * - { start: number, amount: number }<br/>
12
- * - { start: number, end: number }<br/>
13
- * - { start: number, end: [number, boolean] }<br/>
14
- * - { start: [number, boolean] }<br/>
15
- * - { start: [number, boolean], amount: number }<br/>
16
- * - { start: [number, boolean], end: number }<br/>
17
- * - { start: [number, boolean], end: [number, boolean] }<br/>
18
- * - { end: number }<br/>
19
- * - { end: [number, boolean] }<br/>
20
- */
21
- export type IndexRange =
22
- | { amount: number; start?: number | [number, boolean]; end?: undefined }
23
- | Range<number>;
24
-
25
- export namespace IndexRange {
26
- /**
27
- * Returns, given the `range` `IndexRange`, a normalized tuple containing the
28
- * start index, and optionally an end index.
29
- * @param range - the `IndexRange` to use
30
- */
31
- export function getIndexRangeIndices(
32
- range: IndexRange
33
- ): [number, number | undefined] {
34
- if (undefined !== range.amount) {
35
- if (undefined === range.start) return [0, range.amount - 1];
36
-
37
- if (Array.isArray(range.start)) {
38
- const [start, includeStart] = range.start;
39
- if (includeStart) return [start, start + range.amount - 1];
40
- return [start + 1, start + 1 + range.amount - 1];
41
- }
42
- return [range.start, range.start + range.amount - 1];
43
- }
44
-
45
- let start = 0;
46
- let end: number | undefined = undefined;
47
-
48
- if (`start` in range) {
49
- if (Array.isArray(range.start)) {
50
- if (range.start[1]) start = range.start[0];
51
- else start = range.start[0] + 1;
52
- } else start = range.start ?? 0;
53
- }
54
-
55
- if (`end` in range) {
56
- if (Array.isArray(range.end)) {
57
- if (range.end[1]) end = range.end[0];
58
- else end = range.end[0] - 1;
59
- } else end = range.end;
60
- }
61
-
62
- return [start, end];
63
- }
64
-
65
- /**
66
- * Returns, given the `range` `IndexRange`, and a target maximum `length`, the actual index range.
67
- * This can be one of three options:
68
- * - 'empty': there are no elements within the range
69
- * - 'all': all elements are within the range
70
- * - [start: number, end: number]: an inclusive range of element indices within the given range
71
- * @param range - the `IndexRange` to use
72
- * @param length - the target maximum length
73
- */
74
- export function getIndicesFor(
75
- range: IndexRange,
76
- length: number
77
- ): [number, number] | 'empty' | 'all' {
78
- if (length <= 0) return 'empty';
79
-
80
- let start = 0;
81
- let end = length - 1;
82
-
83
- if (undefined !== range.start) {
84
- if (Array.isArray(range.start)) {
85
- start = range.start[0];
86
- if (!range.start[1]) start++;
87
- } else start = range.start;
88
-
89
- if (start >= length || -start > length) return 'empty';
90
- if (start < 0) start = length + start;
91
- }
92
-
93
- if (undefined !== range.amount) {
94
- if (range.amount <= 0) return 'empty';
95
- if (undefined === range.start) {
96
- if (range.amount >= length) return 'all';
97
- return [0, Math.min(end, range.amount - 1)];
98
- }
99
-
100
- end = start + range.amount - 1;
101
- } else if (undefined !== range.end) {
102
- if (Array.isArray(range.end)) {
103
- end = range.end[0];
104
- if (!range.end[1]) {
105
- if (end === 0) return 'empty';
106
- end--;
107
- }
108
- } else end = range.end;
109
-
110
- if (end < 0) end = length + end;
111
- }
112
-
113
- if (end < start) return 'empty';
114
- end = Math.min(length - 1, end);
115
-
116
- if (start === 0 && end === length - 1) return 'all';
117
-
118
- return [start, end];
119
- }
120
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * @packageDocumentation
3
- *
4
- * The `@rimbu/common` package provides shared equality and comparison helpers, range and index
5
- * utilities, lazy and async value helpers, traversal utilities, and rich type‑level helpers used
6
- * throughout the Rimbu ecosystem.<br/>
7
- * Use it when you need well‑tested primitives like `Eq`, `Comp`, `Range`, `OptLazy`, `AsyncOptLazy`,
8
- * or advanced type utilities in your own code, or when building on top of other Rimbu packages.<br/>
9
- * See the [Common docs](https://rimbu.org/docs/common/overview) and
10
- * [API reference](https://rimbu.org/api/rimbu/common) for more information.
11
- */
12
-
13
- export * from './internal.mts';
@@ -1,11 +0,0 @@
1
- export * from './collect.mts';
2
- export * from './comp.mts';
3
- export * from './eq.mts';
4
- export * from './err.mts';
5
- export * from './index-range.mts';
6
- export * from './optlazy.mts';
7
- export * from './range.mts';
8
- export * from './traverse-state.mts';
9
- export * from './types.mts';
10
- export * from './update.mts';
11
- export * from './async-optlazy.mts';
@@ -1,57 +0,0 @@
1
- /**
2
- * A potentially lazy value of type T.
3
- * @typeparam T - the value type
4
- * @typeparam A - (default: []) types of the argument array that can be passed in the lazy case
5
- */
6
- export type OptLazy<T, A extends any[] = []> = T | ((...args: A) => T);
7
-
8
- /**
9
- * Returns the value contained in an `OptLazy` instance of type T.
10
- * @param optLazy - the `OptLazy` value of type T
11
- * @param args - when needed, the extra arguments to pass to the lazy invocation
12
- * @typeparam T - the value type
13
- * @typeparam A - (default: []) types of the argument array that can be passed in the lazy case
14
- * @example
15
- * ```ts
16
- * OptLazy(1) // => 1
17
- * OptLazy(() => 1) // => 1
18
- * OptLazy(() => () => 1) // => () => 1
19
- * ```
20
- */
21
- export function OptLazy<T, A extends any[] = []>(
22
- optLazy: OptLazy<T, A>,
23
- ...args: A
24
- ): T {
25
- if (optLazy instanceof Function) return optLazy(...args);
26
- return optLazy;
27
- }
28
-
29
- /**
30
- * A potentially lazy value that, in case of a lazy function, received a default value
31
- * that it can return.
32
- * @typeparam T - the value type
33
- * @typeparam O - the default value type
34
- */
35
- export type OptLazyOr<T, O> = T | ((none: O) => T | O);
36
-
37
- /**
38
- * Returns the value contained in an `OptLazyOr` instance of type T, or the given
39
- * `otherValue` if the lazy function returns it.
40
- * @param optLazyOr - a value or a function returning a value or otherwise the received value
41
- * @param otherValue - the value to return if the optLazyOr does not return its own value
42
- * @typeparam T - the value type
43
- * @typeparam O - the default value type
44
- * @example
45
- * ```ts
46
- * OptLazyOr(1, 'a') // => 1
47
- * OptLazyOr(() => 1, 'a') // => 1
48
- * OptLazyOr((none) => none, 'a') // => 'a'
49
- * ```
50
- */
51
- export function OptLazyOr<T, O>(
52
- optLazyOr: OptLazyOr<T, O>,
53
- otherValue: O
54
- ): T | O {
55
- if (optLazyOr instanceof Function) return optLazyOr(otherValue);
56
- return optLazyOr;
57
- }