@helpers4/all 2.0.3 → 2.0.4

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/llms.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  # @helpers4/all
2
2
 
3
3
  > Complete collection of tree-shakable TypeScript utility functions.
4
- > Version: 2.0.3 — License: LGPL-3.0-or-later
4
+ > Version: 2.0.4 — License: LGPL-3.0-or-later
5
5
 
6
6
  ## About
7
7
 
@@ -54,6 +54,7 @@ pnpm add @helpers4/version
54
54
  | `@helpers4/array` | `isEmpty` | Checks if an array is empty (has no elements). |
55
55
  | `@helpers4/array` | `isNonEmpty` | Checks if an array is non-empty (has at least one element). |
56
56
  | `@helpers4/array` | `max` | Returns the maximum value in an array using a loop instead of spread, avoiding the call stack overfl |
57
+ | `@helpers4/array` | `mean` | Calculates the arithmetic mean (average) of an array of numbers. Returns `NaN` for an empty array. |
57
58
  | `@helpers4/array` | `min` | Returns the minimum value in an array using a loop instead of spread, avoiding the call stack overfl |
58
59
  | `@helpers4/array` | `partition` | Splits an array into two groups based on a predicate function. The first group contains elements for |
59
60
  | `@helpers4/array` | `range` | Generates an array of sequential numbers from start to end (exclusive). If only one argument is prov |
@@ -66,9 +67,10 @@ pnpm add @helpers4/version
66
67
  | `@helpers4/array` | `sortStringAscInsensitiveFn` | Sort strings in ascending order (case insensitive) |
67
68
  | `@helpers4/array` | `sortStringDescFn` | Sort strings in descending order |
68
69
  | `@helpers4/array` | `sortStringNaturalAscFn` | Sort strings in ascending order using natural (human-friendly) ordering. Numbers embedded in strings |
69
- | `@helpers4/array` | `sortStringNaturalAscInsensitiveFn` | Sort strings in ascending natural order (case insensitive). |
70
+ | `@helpers4/array` | `sortStringNaturalAscInsensitiveFn` | Sort strings in ascending natural order, ignoring case **and diacritics** (`Intl.Collator { sensitiv |
70
71
  | `@helpers4/array` | `sortStringNaturalDescFn` | Sort strings in descending order using natural (human-friendly) ordering. Numbers embedded in string |
71
- | `@helpers4/array` | `sortStringNaturalDescInsensitiveFn` | Sort strings in descending natural order (case insensitive). Numbers embedded in strings are compare |
72
+ | `@helpers4/array` | `sortStringNaturalDescInsensitiveFn` | Sort strings in descending natural order, ignoring case **and diacritics** (`Intl.Collator { sensiti |
73
+ | `@helpers4/array` | `sum` | Calculates the sum of an array of numbers. |
72
74
  | `@helpers4/array` | `unique` | Removes duplicate values from an array |
73
75
  | `@helpers4/array` | `unzip` | Splits an array of tuples into separate arrays, one per position. The inverse of zip. |
74
76
  | `@helpers4/array` | `without` | Returns a new array with all occurrences of the given values removed. Unlike `difference`, which op |
@@ -125,7 +127,7 @@ pnpm add @helpers4/version
125
127
  | `@helpers4/function` | `debounce` | Creates a debounced function that delays invoking func until after delay milliseconds have elapsed s |
126
128
  | `@helpers4/function` | `flip` | Creates a function that invokes `fn` with the first two arguments swapped. Useful when adapting a f |
127
129
  | `@helpers4/function` | `identity` | Returns the given value unchanged Useful as a default transform, in function composition, or as a p |
128
- | `@helpers4/function` | `memoize` | Returns a memoized version of the function that caches results |
130
+ | `@helpers4/function` | `memoize` | Returns a memoized version of the function that caches results. Cache keys are derived via `JSON.st |
129
131
  | `@helpers4/function` | `negate` | Creates a function that negates the result of `predicate`. |
130
132
  | `@helpers4/function` | `noop` | A no-operation function that does nothing and returns `undefined` Useful as a default callback, pla |
131
133
  | `@helpers4/function` | `once` | Creates a function that is restricted to be called only once. Subsequent calls return the cached res |
@@ -149,18 +151,16 @@ pnpm add @helpers4/version
149
151
  | `@helpers4/number` | `isOdd` | Checks if a value is an odd integer. Returns `false` for non-numbers, non-integers, `NaN`, `Infinit |
150
152
  | `@helpers4/number` | `isPositive` | Checks if a value is a number greater than 0. Returns `false` for `NaN`, `0`, negative numbers, and |
151
153
  | `@helpers4/number` | `lerp` | Linearly interpolates between `start` and `end` by the factor `t`. - `t = 0` returns `start`. - `t |
152
- | `@helpers4/number` | `mean` | Calculates the arithmetic mean (average) of an array of numbers. Returns `NaN` for an empty array. |
153
154
  | `@helpers4/number` | `randomBetween` | Generates a random number between min and max (inclusive) |
154
155
  | `@helpers4/number` | `randomIntBetween` | Generates a random integer between min and max (inclusive) |
155
156
  | `@helpers4/number` | `roundTo` | Rounds a number to specified decimal places |
156
- | `@helpers4/number` | `sum` | Calculates the sum of an array of numbers. |
157
157
  | `@helpers4/object` | `compact` | Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `""`, `NaN`) from an objec |
158
158
  | `@helpers4/object` | `deepClone` | Creates a deep copy of an object or array |
159
- | `@helpers4/object` | `deepMerge` | Merges two or more objects deeply |
159
+ | `@helpers4/object` | `deepMerge` | Merges two or more objects deeply. Recursively merges own enumerable properties — both string and s |
160
160
  | `@helpers4/object` | `diff` | Structural object diff. Returns `true` when both inputs are deeply equal, otherwise a DiffResult de |
161
161
  | `@helpers4/object` | `equalsDeep` | Recursive structural object equality. Boolean wrapper around diff \u2014 returns `true` when the tw |
162
162
  | `@helpers4/object` | `equalsShallow` | One-level (shallow) object equality. Two objects are equal when they share the exact same set of ow |
163
- | `@helpers4/object` | `get` | Gets a value from an object using a dot-notated path |
163
+ | `@helpers4/object` | `get` | Gets a value from an object using a dot/bracket-notated path or explicit key array. **Two path form |
164
164
  | `@helpers4/object` | `groupBy` | Groups an array of items by a key derived from each item. A thin, typed wrapper around `Object.grou |
165
165
  | `@helpers4/object` | `invert` | Returns a new object with keys and values swapped. If multiple keys share the same value, the last o |
166
166
  | `@helpers4/object` | `isEmpty` | Checks if a plain object has no own enumerable string-keyed properties. Symbol-keyed properties are |
@@ -170,7 +170,7 @@ pnpm add @helpers4/version
170
170
  | `@helpers4/object` | `pick` | Creates a new object with only the specified keys. |
171
171
  | `@helpers4/object` | `removeUndefinedNull` | Remove null and undefined values from an object. |
172
172
  | `@helpers4/object` | `safeJsonParse` | Parses a JSON string, returning `null` (or a fallback) on any parse failure. Unlike `JSON.parse`, t |
173
- | `@helpers4/object` | `set` | Sets a value in an object using a dot-notated path |
173
+ | `@helpers4/object` | `set` | Sets a value in an object at the given path, creating intermediate objects as needed. **Three path |
174
174
  | `@helpers4/observable` | `combine` | Combine two observables with a map function and an optional pre-treatment. Note: you can use the pr |
175
175
  | `@helpers4/observable` | `combineLatest` | Combines multiple Observables to create an Observable whose values are calculated from the latest va |
176
176
  | `@helpers4/observable` | `isObservable` | Checks if a value is an RxJS Observable or any compatible observable. Uses duck-typing: returns `tr |
@@ -463,10 +463,30 @@ createSortByDateFn<T extends Record<string, unknown>>(property?: keyof T): SortF
463
463
 
464
464
  **Parameters:**
465
465
 
466
- - `property?: keyof T` — The property to sort by (defaults to 'date')
466
+ - `property?: keyof T` — The property to sort by (defaults to `'date'`).
467
+ Accepted value types: `Date` (including cross-realm instances), `string`, or
468
+ `number` (Unix milliseconds). Any object with a `getTime(): number` method is
469
+ also accepted (duck-typed, so cross-realm `Date` objects work correctly).
470
+ `null`, `undefined`, and unparseable strings produce `NaN` and sort last,
471
+ distinct from a genuine Unix-epoch date (`new Date(0)`).
467
472
 
468
473
  **Returns:** `SortFn<T>` — Sort function
469
474
 
475
+ **Examples:**
476
+
477
+ *createSortByDateFn*
478
+
479
+ ```typescript
480
+ ```ts
481
+ const events = [
482
+ { date: new Date('2023-01-01') },
483
+ { date: new Date('2021-06-15') },
484
+ ];
485
+ events.sort(createSortByDateFn('date'))
486
+ // => sorted oldest first
487
+ ```
488
+ ```
489
+
470
490
  ---
471
491
 
472
492
  ### `createSortByNaturalFn`
@@ -488,11 +508,23 @@ createSortByNaturalFn<T extends Record<string, unknown>>(property?: keyof T | re
488
508
  Defaults to trying 'value', 'label', 'title', 'description' in that order.
489
509
  - `caseInsensitive: boolean` (default: `false`) — Whether to ignore case **and diacritics** (default: false).
490
510
  Uses `Intl.Collator { sensitivity: 'base' }`, which treats é, E, and e as equal.
491
- This differs from `createSortByStringFn(key, true)`, which only folds case via
492
- `toLowerCase` and still distinguishes accented characters.
511
+ This differs from `createSortByStringFn(key, true)`, which only folds case and
512
+ still distinguishes accented characters (é ≠ e).
493
513
 
494
514
  **Returns:** `SortFn<T>` — Sort function
495
515
 
516
+ **Examples:**
517
+
518
+ *createSortByNaturalFn*
519
+
520
+ ```typescript
521
+ ```ts
522
+ const items = [{ label: 'W11' }, { label: 'W2' }, { label: 'W20' }];
523
+ items.sort(createSortByNaturalFn('label'))
524
+ // => [{ label: 'W2' }, { label: 'W11' }, { label: 'W20' }]
525
+ ```
526
+ ```
527
+
496
528
  ---
497
529
 
498
530
  ### `createSortByNumberFn`
@@ -507,10 +539,27 @@ createSortByNumberFn<T extends Record<string, unknown>>(property?: keyof T): Sor
507
539
 
508
540
  **Parameters:**
509
541
 
510
- - `property?: keyof T` — The property to sort by (defaults to 'value')
542
+ - `property?: keyof T` — The property to sort by (defaults to `'value'`). Always pass an
543
+ explicit key when T does not have a `'value'` property — omitting it on such types
544
+ produces a no-op comparator (all elements compare equal).
545
+ `null` and `undefined` sort last (treated as `+Infinity`). Non-numeric values
546
+ (including booleans — `Number(true) === 1`, `Number(false) === 0`) and `NaN` also
547
+ sort last.
511
548
 
512
549
  **Returns:** `SortFn<T>` — Sort function
513
550
 
551
+ **Examples:**
552
+
553
+ *createSortByNumberFn*
554
+
555
+ ```typescript
556
+ ```ts
557
+ const items = [{ count: 3 }, { count: 1 }, { count: 2 }];
558
+ items.sort(createSortByNumberFn('count'))
559
+ // => [{ count: 1 }, { count: 2 }, { count: 3 }]
560
+ ```
561
+ ```
562
+
514
563
  ---
515
564
 
516
565
  ### `createSortByStringFn`
@@ -519,6 +568,10 @@ Creates a sort function for objects by one or more string properties.
519
568
  When multiple properties are given the array is sorted by the first key;
520
569
  ties are broken by the second key, then the third, and so on.
521
570
 
571
+ Property values are coerced to strings via `String()` before comparison:
572
+ numbers sort as `'0'`, `'1'`, `'42'`, etc. (lexicographic, not numeric);
573
+ use `createSortByNumberFn` for numeric properties.
574
+
522
575
  ```typescript
523
576
  import { createSortByStringFn } from '@helpers4/array';
524
577
 
@@ -529,7 +582,12 @@ createSortByStringFn<T extends Record<string, unknown>>(property?: keyof T | rea
529
582
 
530
583
  - `property?: keyof T | readonly keyof T[]` — The property (or ordered list of properties) to sort by.
531
584
  Defaults to trying 'value', 'label', 'title', 'description' in that order.
532
- - `caseInsensitive: boolean` (default: `false`) Whether to ignore case (default: false)
585
+ Pass `undefined` explicitly to use auto-detect; an empty array `[]` produces a
586
+ stable no-op comparator (does **not** fall back to auto-detect).
587
+ - `caseInsensitive: boolean` (default: `false`) — Whether to ignore case (default: false).
588
+ Uses `Intl.Collator { sensitivity: 'accent' }`, which folds case but still
589
+ distinguishes accented characters (é ≠ e). This differs from
590
+ `createSortByNaturalFn(key, true)`, which also collapses diacritics.
533
591
 
534
592
  **Returns:** `SortFn<T>` — Sort function
535
593
 
@@ -1012,6 +1070,39 @@ max(Array.from({ length: 1_000_000 }, (_, i) => i))
1012
1070
 
1013
1071
  ---
1014
1072
 
1073
+ ### `mean`
1074
+
1075
+ Calculates the arithmetic mean (average) of an array of numbers.
1076
+ Returns `NaN` for an empty array.
1077
+
1078
+ Pairs with sum for aggregate operations.
1079
+
1080
+ ```typescript
1081
+ import { mean } from '@helpers4/array';
1082
+
1083
+ mean(array: readonly number[]): number
1084
+ ```
1085
+
1086
+ **Parameters:**
1087
+
1088
+ - `array: readonly number[]` — The array of numbers to average
1089
+
1090
+ **Returns:** `number` — The arithmetic mean, or `NaN` if the array is empty
1091
+
1092
+ **Examples:**
1093
+
1094
+ *Average a list of numbers*
1095
+
1096
+ Returns the arithmetic mean of the array; NaN for empty arrays.
1097
+
1098
+ ```typescript
1099
+ mean([1, 2, 3, 4]) // => 2.5
1100
+ mean([10, 20, 30]) // => 20
1101
+ mean([]) // => NaN
1102
+ ```
1103
+
1104
+ ---
1105
+
1015
1106
  ### `min`
1016
1107
 
1017
1108
  Returns the minimum value in an array using a loop instead of spread,
@@ -1394,7 +1485,19 @@ items.sort(createSortByNaturalFn('code'))
1394
1485
 
1395
1486
  ### `sortStringNaturalAscInsensitiveFn`
1396
1487
 
1397
- Sort strings in ascending natural order (case insensitive).
1488
+ Sort strings in ascending natural order, ignoring case **and diacritics**
1489
+ (`Intl.Collator { sensitivity: 'base' }` — treats é, E, and e as equal).
1490
+ Numbers embedded in strings are compared numerically: "W2" < "W11" < "W20".
1491
+
1492
+ **Examples:**
1493
+
1494
+ *sortStringNaturalAscInsensitiveFn*
1495
+
1496
+ ```typescript
1497
+ ```ts
1498
+ ['W11', 'W2', 'W20'].sort(sortStringNaturalAscInsensitiveFn) // => ['W2', 'W11', 'W20']
1499
+ ```
1500
+ ```
1398
1501
 
1399
1502
  ---
1400
1503
 
@@ -1403,13 +1506,72 @@ Sort strings in ascending natural order (case insensitive).
1403
1506
  Sort strings in descending order using natural (human-friendly) ordering.
1404
1507
  Numbers embedded in strings are compared numerically: "W20" > "W11" > "W2".
1405
1508
 
1509
+ **Examples:**
1510
+
1511
+ *sortStringNaturalDescFn*
1512
+
1513
+ ```typescript
1514
+ ```ts
1515
+ ['W11', 'W2', 'W20'].sort(sortStringNaturalDescFn) // => ['W20', 'W11', 'W2']
1516
+ ```
1517
+ ```
1518
+
1406
1519
  ---
1407
1520
 
1408
1521
  ### `sortStringNaturalDescInsensitiveFn`
1409
1522
 
1410
- Sort strings in descending natural order (case insensitive).
1523
+ Sort strings in descending natural order, ignoring case **and diacritics**
1524
+ (`Intl.Collator { sensitivity: 'base' }` — treats é, E, and e as equal).
1411
1525
  Numbers embedded in strings are compared numerically: "W20" > "W11" > "W2".
1412
1526
 
1527
+ **Examples:**
1528
+
1529
+ *sortStringNaturalDescInsensitiveFn*
1530
+
1531
+ ```typescript
1532
+ ```ts
1533
+ ['W11', 'W2', 'W20'].sort(sortStringNaturalDescInsensitiveFn) // => ['W20', 'W11', 'W2']
1534
+ ```
1535
+ ```
1536
+
1537
+ ---
1538
+
1539
+ ### `sum`
1540
+
1541
+ Calculates the sum of an array of numbers.
1542
+
1543
+ ```typescript
1544
+ import { sum } from '@helpers4/array';
1545
+
1546
+ sum(array: readonly number[]): number
1547
+ ```
1548
+
1549
+ **Parameters:**
1550
+
1551
+ - `array: readonly number[]` — The array of numbers to sum
1552
+
1553
+ **Returns:** `number` — The sum of all values, or `0` for an empty array
1554
+
1555
+ **Examples:**
1556
+
1557
+ *Sum numbers*
1558
+
1559
+ Calculates the sum of an array of numbers.
1560
+
1561
+ ```typescript
1562
+ sum([1, 2, 3, 4])
1563
+ // => 10
1564
+ ```
1565
+
1566
+ *Sum with negative numbers*
1567
+
1568
+ Handles negative numbers correctly.
1569
+
1570
+ ```typescript
1571
+ sum([10, -3, 5, -2])
1572
+ // => 10
1573
+ ```
1574
+
1413
1575
  ---
1414
1576
 
1415
1577
  ### `unique`
@@ -3700,17 +3862,23 @@ Pass identity where a transform function is required but no transformation is ne
3700
3862
 
3701
3863
  ### `memoize`
3702
3864
 
3703
- Returns a memoized version of the function that caches results
3865
+ Returns a memoized version of the function that caches results.
3866
+
3867
+ Cache keys are derived via `JSON.stringify`; `undefined` arguments are
3868
+ correctly distinguished from `null`. Arguments that are not JSON-serializable
3869
+ (functions, symbols, class instances, circular references) produce a
3870
+ `null`-equivalent key and are not supported.
3704
3871
 
3705
3872
  ```typescript
3706
3873
  import { memoize } from '@helpers4/function';
3707
3874
 
3708
- memoize<A extends unknown[], R>(func: function): function
3875
+ memoize<A extends unknown[], R>(func: function, options?: MemoizeOptions): function
3709
3876
  ```
3710
3877
 
3711
3878
  **Parameters:**
3712
3879
 
3713
3880
  - `func: function` — The function to memoize
3881
+ - `options?: MemoizeOptions` — Optional settings (e.g. `maxSize` to cap memory usage)
3714
3882
 
3715
3883
  **Returns:** `function` — The memoized function
3716
3884
 
@@ -4515,6 +4683,10 @@ Note: for values whose integer part already consumes 14 or more digits
4515
4683
  digits and will silently truncate them. Increase `precision` if you
4516
4684
  need to correct drift in very large numbers.
4517
4685
 
4686
+ Note: IEEE-754 doubles carry at most ~17 significant decimal digits.
4687
+ Precision values above 17 pad with digits that reflect the underlying
4688
+ binary representation rather than correcting drift.
4689
+
4518
4690
  ```typescript
4519
4691
  import { correctFloat } from '@helpers4/number';
4520
4692
 
@@ -4524,7 +4696,9 @@ correctFloat(value: number, precision: number): number
4524
4696
  **Parameters:**
4525
4697
 
4526
4698
  - `value: number` — The floating-point value to correct
4527
- - `precision: number` (default: `14`) — Integer number of significant digits (default: 14)
4699
+ - `precision: number` (default: `14`) — Integer number of significant digits between 1 and 100
4700
+ (default: 14). Values above 17 are valid but expose binary noise beyond
4701
+ IEEE-754's meaningful range.
4528
4702
 
4529
4703
  **Returns:** `number` — The corrected value
4530
4704
 
@@ -4581,9 +4755,12 @@ extractNumber(value: unknown, options: ExtractNumberOptions): number | undefined
4581
4755
  ```typescript
4582
4756
  ```ts
4583
4757
  extractNumber('16.5px') // => 16.5
4758
+ extractNumber('.5rem') // => 0.5 (leading-dot decimal)
4759
+ extractNumber('-.5') // => -0.5 (leading-dot with sign)
4584
4760
  extractNumber('Wafer 10') // => 10
4585
4761
  extractNumber('xxx-111') // => 111 ('-' glued to text → separator)
4586
4762
  extractNumber('xxx -111') // => -111 ('-' preceded by a space → sign)
4763
+ extractNumber('x-.5') // => 0.5 ('-' glued to 'x' → separator; leading-dot decimal follows)
4587
4764
  extractNumber('-111') // => -111 ('-' at the start of the string → sign)
4588
4765
  extractNumber('1e5 mol') // => 100000
4589
4766
  extractNumber('1e5kg') // => 1 ('e5' glued to text → mantissa only)
@@ -4917,39 +5094,6 @@ lerp(0, 10, 2) // => 20 (extrapolation)
4917
5094
 
4918
5095
  ---
4919
5096
 
4920
- ### `mean`
4921
-
4922
- Calculates the arithmetic mean (average) of an array of numbers.
4923
- Returns `NaN` for an empty array.
4924
-
4925
- Pairs with sum for aggregate operations.
4926
-
4927
- ```typescript
4928
- import { mean } from '@helpers4/number';
4929
-
4930
- mean(array: readonly number[]): number
4931
- ```
4932
-
4933
- **Parameters:**
4934
-
4935
- - `array: readonly number[]` — The array of numbers to average
4936
-
4937
- **Returns:** `number` — The arithmetic mean, or `NaN` if the array is empty
4938
-
4939
- **Examples:**
4940
-
4941
- *Average a list of numbers*
4942
-
4943
- Returns the arithmetic mean of the array; NaN for empty arrays.
4944
-
4945
- ```typescript
4946
- mean([1, 2, 3, 4]) // => 2.5
4947
- mean([10, 20, 30]) // => 20
4948
- mean([]) // => NaN
4949
- ```
4950
-
4951
- ---
4952
-
4953
5097
  ### `randomBetween`
4954
5098
 
4955
5099
  Generates a random number between min and max (inclusive)
@@ -5047,44 +5191,6 @@ roundTo(3.7, 0)
5047
5191
 
5048
5192
  ---
5049
5193
 
5050
- ### `sum`
5051
-
5052
- Calculates the sum of an array of numbers.
5053
-
5054
- ```typescript
5055
- import { sum } from '@helpers4/number';
5056
-
5057
- sum(array: readonly number[]): number
5058
- ```
5059
-
5060
- **Parameters:**
5061
-
5062
- - `array: readonly number[]` — The array of numbers to sum
5063
-
5064
- **Returns:** `number` — The sum of all values
5065
-
5066
- **Examples:**
5067
-
5068
- *Sum numbers*
5069
-
5070
- Calculates the sum of an array of numbers.
5071
-
5072
- ```typescript
5073
- sum([1, 2, 3, 4])
5074
- // => 10
5075
- ```
5076
-
5077
- *Sum with negative numbers*
5078
-
5079
- Handles negative numbers correctly.
5080
-
5081
- ```typescript
5082
- sum([10, -3, 5, -2])
5083
- // => 10
5084
- ```
5085
-
5086
- ---
5087
-
5088
5194
  ## object
5089
5195
 
5090
5196
  Package: `@helpers4/object`
@@ -5184,46 +5290,51 @@ cloned.a.b = 2;
5184
5290
 
5185
5291
  ### `deepMerge`
5186
5292
 
5187
- Merges two or more objects deeply
5293
+ Merges two or more objects deeply.
5294
+
5295
+ Recursively merges own enumerable properties — both string and symbol keys.
5296
+ Plain objects are merged recursively; all other values (arrays, class instances,
5297
+ primitives, etc.) are replaced by the source value.
5298
+ `undefined` source values do not overwrite existing target values.
5188
5299
 
5189
5300
  ```typescript
5190
5301
  import { deepMerge } from '@helpers4/object';
5191
5302
 
5192
- deepMerge<T extends Record<string, unknown>>(target: T, sources: Record<string, unknown>[]): T
5303
+ deepMerge<T extends Record<PropertyKey, unknown>>(target: T, sources: Record<PropertyKey, unknown>[]): T
5193
5304
  ```
5194
5305
 
5195
5306
  **Parameters:**
5196
5307
 
5197
- - `target: T` — The target object
5198
- - `sources: Record<string, unknown>[]` — The source objects to merge
5308
+ - `target: T` — The target object (mutated in place)
5309
+ - `sources: Record<PropertyKey, unknown>[]` — One or more source objects to merge into the target
5199
5310
 
5200
- **Returns:** `T` — The merged object
5311
+ **Returns:** `T` — The mutated target
5201
5312
 
5202
5313
  ```typescript
5203
5314
  import { deepMerge } from '@helpers4/object';
5204
5315
 
5205
- deepMerge(target: undefined, sources: Record<string, unknown>[]): undefined
5316
+ deepMerge(target: undefined, sources: Record<PropertyKey, unknown>[]): undefined
5206
5317
  ```
5207
5318
 
5208
5319
  **Parameters:**
5209
5320
 
5210
- - `target: undefined` — The target object
5211
- - `sources: Record<string, unknown>[]` — The source objects to merge
5321
+ - `target: undefined` — The target object (mutated in place)
5322
+ - `sources: Record<PropertyKey, unknown>[]` — One or more source objects to merge into the target
5212
5323
 
5213
- **Returns:** `undefined` — The merged object
5324
+ **Returns:** `undefined` — The mutated target
5214
5325
 
5215
5326
  ```typescript
5216
5327
  import { deepMerge } from '@helpers4/object';
5217
5328
 
5218
- deepMerge(target: null, sources: Record<string, unknown>[]): null
5329
+ deepMerge(target: null, sources: Record<PropertyKey, unknown>[]): null
5219
5330
  ```
5220
5331
 
5221
5332
  **Parameters:**
5222
5333
 
5223
- - `target: null` — The target object
5224
- - `sources: Record<string, unknown>[]` — The source objects to merge
5334
+ - `target: null` — The target object (mutated in place)
5335
+ - `sources: Record<PropertyKey, unknown>[]` — One or more source objects to merge into the target
5225
5336
 
5226
- **Returns:** `null` — The merged object
5337
+ **Returns:** `null` — The mutated target
5227
5338
 
5228
5339
  **Examples:**
5229
5340
 
@@ -5383,7 +5494,17 @@ equalsShallow({ a: 1, b: 2 }, { a: 1, b: 2 })
5383
5494
 
5384
5495
  ### `get`
5385
5496
 
5386
- Gets a value from an object using a dot-notated path
5497
+ Gets a value from an object using a dot/bracket-notated path or explicit key array.
5498
+
5499
+ **Two path forms are supported:**
5500
+
5501
+ 1. **String path** — dot notation (`'a.b.c'`) and bracket notation (`'layers[1].name'`)
5502
+ are both accepted and mixed freely. Segments are traversed as string keys; `[n]`
5503
+ indices become numeric keys.
5504
+
5505
+ 2. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,
5506
+ no parsing performed. Enables symbol-keyed traversal and compile-time type inference:
5507
+ `get(obj, ['a', 'b'] as const)` infers the return type from the path.
5387
5508
 
5388
5509
  ```typescript
5389
5510
  import { get } from '@helpers4/object';
@@ -5393,11 +5514,25 @@ get<T = unknown>(obj: unknown, path: string, defaultValue?: T): T | undefined
5393
5514
 
5394
5515
  **Parameters:**
5395
5516
 
5396
- - `obj: unknown` — The object to get value from
5397
- - `path: string` — The dot-notated path (e.g., 'a.b.c')
5398
- - `defaultValue?: T` — Default value if path doesn't exist
5517
+ - `obj: unknown` — The object to read from
5518
+ - `path: string` — Dot/bracket-notation string or explicit `PropertyKey[]`
5519
+ - `defaultValue?: T` — Returned when the path is absent or resolves to `undefined`
5520
+
5521
+ **Returns:** `T | undefined` — The value at the path, or `defaultValue`
5522
+
5523
+ ```typescript
5524
+ import { get } from '@helpers4/object';
5525
+
5526
+ get<T extends object, Path extends readonly PropertyKey[]>(obj: T, path: Path, defaultValue?: DeepGet<T, Path>): DeepGet<T, Path> | undefined
5527
+ ```
5528
+
5529
+ **Parameters:**
5530
+
5531
+ - `obj: T` — The object to read from
5532
+ - `path: Path` — Dot/bracket-notation string or explicit `PropertyKey[]`
5533
+ - `defaultValue?: DeepGet<T, Path>` — Returned when the path is absent or resolves to `undefined`
5399
5534
 
5400
- **Returns:** `T | undefined` — The value at the path or default value
5535
+ **Returns:** `DeepGet<T, Path> | undefined` — The value at the path, or `defaultValue`
5401
5536
 
5402
5537
  **Examples:**
5403
5538
 
@@ -5419,6 +5554,16 @@ get({ a: 1 }, 'b.c', 'default')
5419
5554
  // => 'default'
5420
5555
  ```
5421
5556
 
5557
+ *Get via key array (supports symbols)*
5558
+
5559
+ Pass an explicit PropertyKey[] to bypass parsing. Supports string, number, and symbol keys.
5560
+
5561
+ ```typescript
5562
+ const id = Symbol('id')
5563
+ get({ [id]: 'alice' }, [id])
5564
+ // => 'alice'
5565
+ ```
5566
+
5422
5567
  ---
5423
5568
 
5424
5569
  ### `groupBy`
@@ -5913,7 +6058,24 @@ safeJsonParse('invalid', [])
5913
6058
 
5914
6059
  ### `set`
5915
6060
 
5916
- Sets a value in an object using a dot-notated path
6061
+ Sets a value in an object at the given path, creating intermediate objects as needed.
6062
+
6063
+ **Three path forms are supported:**
6064
+
6065
+ 1. **Dot notation** (`string`) — segments split on `.` are kept as-is string keys.
6066
+ `"layers.1.name"` → keys `["layers", "1", "name"]` (all strings, including `"1"`).
6067
+
6068
+ 2. **Bracket notation** (`string`) — `[n]` segments are parsed as numeric keys.
6069
+ `"layers[1].name"` → keys `["layers", 1, "name"]` (index `1` becomes a number).
6070
+ Dot and bracket can be mixed freely: `"a[0].b[2].c"`.
6071
+
6072
+ 3. **Key array** (`PropertyKey[]`) — explicit array of `string | number | symbol` keys,
6073
+ no parsing performed. Enables full key-type control, including symbols:
6074
+ `["layers", 1, Symbol('id')]`.
6075
+
6076
+ Intermediate nodes that are absent, `null`, or not an object are replaced with `{}`.
6077
+ Any path containing a string segment equal to `__proto__`, `constructor`, or `prototype`
6078
+ is rejected and the original object is returned unchanged (prototype-pollution guard).
5917
6079
 
5918
6080
  ```typescript
5919
6081
  import { set } from '@helpers4/object';
@@ -5923,21 +6085,58 @@ set(obj: Record<string, unknown>, path: string, value: unknown): Record<string,
5923
6085
 
5924
6086
  **Parameters:**
5925
6087
 
5926
- - `obj: Record<string, unknown>` — The object to set value in
5927
- - `path: string` — The dot-notated path (e.g., 'a.b.c')
5928
- - `value: unknown` — The value to set
6088
+ - `obj: Record<string, unknown>` — The object to mutate
6089
+ - `path: string` — Dot/bracket-notation string or explicit `PropertyKey[]`
6090
+ - `value: unknown` — Value to assign at the path
5929
6091
 
5930
- **Returns:** `Record<string, unknown>` — The modified object
6092
+ **Returns:** `Record<string, unknown>` — The mutated object (same reference)
6093
+
6094
+ ```typescript
6095
+ import { set } from '@helpers4/object';
6096
+
6097
+ set<T extends object, Path extends readonly PropertyKey[], V extends unknown>(obj: T, path: Path, value: V): DeepSet<T, Path, V>
6098
+ ```
6099
+
6100
+ **Parameters:**
6101
+
6102
+ - `obj: T` — The object to mutate
6103
+ - `path: Path` — Dot/bracket-notation string or explicit `PropertyKey[]`
6104
+ - `value: V` — Value to assign at the path
6105
+
6106
+ **Returns:** `DeepSet<T, Path, V>` — The mutated object (same reference)
5931
6107
 
5932
6108
  **Examples:**
5933
6109
 
5934
- *Set a nested property*
6110
+ *Set a nested property (dot notation)*
5935
6111
 
5936
- Creates intermediate objects as needed along the dot-notated path.
6112
+ Creates intermediate objects as needed. All segments are string keys — including numeric-looking ones like "1".
5937
6113
 
5938
6114
  ```typescript
5939
6115
  set({}, 'a.b.c', 42)
5940
6116
  // => { a: { b: { c: 42 } } }
6117
+
6118
+ set({}, 'layers.1.name', 'bg')
6119
+ // => { layers: { '1': { name: 'bg' } } } // '1' is a string key
6120
+ ```
6121
+
6122
+ *Set via bracket notation*
6123
+
6124
+ Square-bracket indices become numeric keys. Useful when the path targets an array element.
6125
+
6126
+ ```typescript
6127
+ const obj = { layers: [{}, { name: 'old' }] }
6128
+ set(obj, 'layers[1].name', 'new')
6129
+ // => { layers: [{}, { name: 'new' }] }
6130
+ ```
6131
+
6132
+ *Set via key array (supports symbols)*
6133
+
6134
+ Pass an explicit PropertyKey[] to bypass parsing. Supports string, number, and symbol keys.
6135
+
6136
+ ```typescript
6137
+ const id = Symbol('id')
6138
+ set({}, ['user', id], 'alice')
6139
+ // => { user: { [id]: 'alice' } }
5941
6140
  ```
5942
6141
 
5943
6142
  ---
@@ -7747,6 +7946,10 @@ type MutableConfig = DeepWritable<Config>;
7747
7946
  type Point = readonly [x: number, y: number];
7748
7947
  type MutablePoint = DeepWritable<Point>;
7749
7948
  // => [x: number, y: number]
7949
+
7950
+ Note: `Date`, `Map`, `Set`, `Promise`, and `RegExp` are treated as opaque and passed
7951
+ through unchanged. In particular, `DeepWritable<Map<K, V>>` does **not** strip `readonly`
7952
+ from the value type `V` — use a manual mapped type if you need that.
7750
7953
  ```
7751
7954
  ```
7752
7955
 
package/meta/build.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
- "buildDate": "2026-06-16T21:13:06.456Z",
3
- "version": "2.0.3",
4
- "mutationDashboardUrl": "https://dashboard.stryker-mutator.io/reports/github.com/helpers4/typescript/v2.0.3",
2
+ "buildDate": "2026-06-21T11:57:07.644Z",
3
+ "version": "2.0.4",
4
+ "mutationDashboardUrl": "https://dashboard.stryker-mutator.io/reports/github.com/helpers4/typescript/v2.0.4",
5
5
  "runtimes": {
6
6
  "node": ">=20.0.0",
7
7
  "deno": "compatible",
@@ -1,19 +1,19 @@
1
1
  {
2
- "@helpers4/all": "2.0.3",
3
- "@helpers4/array": "2.0.3",
4
- "@helpers4/ci": "2.0.3",
5
- "@helpers4/commit": "2.0.3",
6
- "@helpers4/date": "2.0.3",
7
- "@helpers4/function": "2.0.3",
8
- "@helpers4/id": "2.0.3",
9
- "@helpers4/markdown": "2.0.3",
10
- "@helpers4/node": "2.0.3",
11
- "@helpers4/number": "2.0.3",
12
- "@helpers4/object": "2.0.3",
13
- "@helpers4/observable": "2.0.3",
14
- "@helpers4/promise": "2.0.3",
15
- "@helpers4/string": "2.0.3",
16
- "@helpers4/type": "2.0.3",
17
- "@helpers4/url": "2.0.3",
18
- "@helpers4/version": "2.0.3"
2
+ "@helpers4/all": "2.0.4",
3
+ "@helpers4/array": "2.0.4",
4
+ "@helpers4/ci": "2.0.4",
5
+ "@helpers4/commit": "2.0.4",
6
+ "@helpers4/date": "2.0.4",
7
+ "@helpers4/function": "2.0.4",
8
+ "@helpers4/id": "2.0.4",
9
+ "@helpers4/markdown": "2.0.4",
10
+ "@helpers4/node": "2.0.4",
11
+ "@helpers4/number": "2.0.4",
12
+ "@helpers4/object": "2.0.4",
13
+ "@helpers4/observable": "2.0.4",
14
+ "@helpers4/promise": "2.0.4",
15
+ "@helpers4/string": "2.0.4",
16
+ "@helpers4/type": "2.0.4",
17
+ "@helpers4/url": "2.0.4",
18
+ "@helpers4/version": "2.0.4"
19
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helpers4/all",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "Complete collection of helpers4 utilities - all categories in one convenient package.",
5
5
  "author": "baxyz <baxy@etik.com>",
6
6
  "license": "LGPL-3.0",
@@ -27,21 +27,21 @@
27
27
  "llms.txt"
28
28
  ],
29
29
  "peerDependencies": {
30
- "@helpers4/array": "2.0.3",
31
- "@helpers4/ci": "2.0.3",
32
- "@helpers4/commit": "2.0.3",
33
- "@helpers4/date": "2.0.3",
34
- "@helpers4/function": "2.0.3",
35
- "@helpers4/id": "2.0.3",
36
- "@helpers4/markdown": "2.0.3",
37
- "@helpers4/node": "2.0.3",
38
- "@helpers4/number": "2.0.3",
39
- "@helpers4/object": "2.0.3",
40
- "@helpers4/observable": "2.0.3",
41
- "@helpers4/promise": "2.0.3",
42
- "@helpers4/string": "2.0.3",
43
- "@helpers4/type": "2.0.3",
44
- "@helpers4/url": "2.0.3",
45
- "@helpers4/version": "2.0.3"
30
+ "@helpers4/array": "2.0.4",
31
+ "@helpers4/ci": "2.0.4",
32
+ "@helpers4/commit": "2.0.4",
33
+ "@helpers4/date": "2.0.4",
34
+ "@helpers4/function": "2.0.4",
35
+ "@helpers4/id": "2.0.4",
36
+ "@helpers4/markdown": "2.0.4",
37
+ "@helpers4/node": "2.0.4",
38
+ "@helpers4/number": "2.0.4",
39
+ "@helpers4/object": "2.0.4",
40
+ "@helpers4/observable": "2.0.4",
41
+ "@helpers4/promise": "2.0.4",
42
+ "@helpers4/string": "2.0.4",
43
+ "@helpers4/type": "2.0.4",
44
+ "@helpers4/url": "2.0.4",
45
+ "@helpers4/version": "2.0.4"
46
46
  }
47
47
  }