@helpers4/object 3.0.2 → 3.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/object
2
2
 
3
3
  > Tree-shakable TypeScript utility functions for the `object` domain.
4
- > Package: `@helpers4/object` — Version: 3.0.2
4
+ > Package: `@helpers4/object` — Version: 3.0.4
5
5
  > License: LGPL-3.0-or-later
6
6
 
7
7
  ## Installation
@@ -15,13 +15,14 @@ pnpm add @helpers4/object
15
15
  ## Usage
16
16
 
17
17
  ```typescript
18
- import { clone, cloneDeep, compact, ... } from '@helpers4/object';
18
+ import { camelCaseKeys, clone, cloneDeep, ... } from '@helpers4/object';
19
19
  ```
20
20
 
21
21
  ## Functions
22
22
 
23
23
  | Function | Description |
24
24
  |---|---|
25
+ | `camelCaseKeys` | Recursively transforms every key of a plain object (including keys nested inside arrays and nested o |
25
26
  | `clone` | Creates a shallow copy of a value — one level deep, unlike cloneDeep. Unlike a plain `{ ...value }` |
26
27
  | `cloneDeep` | Creates a deep copy of an object or array. Recursively clones own enumerable string keys. `Date` in |
27
28
  | `compact` | Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `""`, `NaN`) from an objec |
@@ -34,16 +35,22 @@ import { clone, cloneDeep, compact, ... } from '@helpers4/object';
34
35
  | `invert` | Returns a new object with keys and values swapped. If multiple keys share the same value, the last o |
35
36
  | `isEmpty` | Checks if a plain object has no own enumerable string-keyed properties. `null` and `undefined` are t |
36
37
  | `isNonEmpty` | Checks if a plain object has at least one own enumerable string-keyed property. `null` and `undefine |
38
+ | `kebabCaseKeys` | Recursively transforms every key of a plain object (including keys nested inside arrays and nested o |
37
39
  | `map` | Transforms the values and/or keys of a plain object in a single pass. Both callbacks are optional a |
40
+ | `mapDeep` | Recursively transforms the keys and/or values of a plain object — the deep counterpart to map, which |
38
41
  | `mergeDeep` | Merges two or more objects deeply, returning a **new** object without mutating any input. Sources a |
39
42
  | `omit` | Creates a new object without the specified keys. |
40
43
  | `omitBy` | Creates a new object without the own enumerable entries for which `predicate` returns `true`. Compl |
41
44
  | `parsePropertyPath` | Parses a dot/bracket-notation property path into an array of string/number key segments — the same n |
45
+ | `pascalCaseKeys` | Recursively transforms every key of a plain object (including keys nested inside arrays and nested o |
42
46
  | `pick` | Creates a new object with only the specified keys. Keys that are prototype-polluting strings (`__pro |
43
47
  | `pickBy` | Creates a new object with only the own enumerable entries for which `predicate` returns `true`. Com |
44
48
  | `removeUndefinedNull` | Remove null and undefined values from an object. |
45
49
  | `safeJsonParse` | Parses a JSON string, returning `null` (or a fallback) on any parse failure. Unlike `JSON.parse`, t |
46
50
  | `set` | Sets a value in an object at the given path, creating intermediate objects as needed. **Two path fo |
51
+ | `snakeCaseKeys` | Recursively transforms every key of a plain object (including keys nested inside arrays and nested o |
52
+ | `sortKeys` | Creates a new object with the same entries as the input, but with its own keys sorted. Shallow only |
53
+ | `titleCaseKeys` | Recursively transforms every key of a plain object (including keys nested inside arrays and nested o |
47
54
  | `unflatten` | Rebuilds a nested object from a single-level object whose keys are dot-notation paths. The inverse o |
48
55
  | `unset` | Removes the value at a dot/bracket-notation path or explicit key array, mutating the object in place |
49
56
  | `update` | Updates the value at a path by applying a function to its current value, creating intermediate objec |
@@ -52,6 +59,49 @@ import { clone, cloneDeep, compact, ... } from '@helpers4/object';
52
59
 
53
60
  ## API Reference
54
61
 
62
+ ### `camelCaseKeys`
63
+
64
+ Recursively transforms every key of a plain object (including keys nested inside arrays and
65
+ nested objects) to camelCase. Handles snake_case, kebab-case, PascalCase, and space-separated
66
+ keys. Non-plain-object values (arrays' items aside) — `Date`, `Map`, `Set`, class instances,
67
+ primitives — are left untouched, only their position is walked into. An entry whose
68
+ transformed key is a prototype-polluting string (`__proto__`, `constructor`, `prototype`) is
69
+ silently skipped, same as the rest of `@helpers4/object`.
70
+
71
+ ```typescript
72
+ import { camelCaseKeys } from '@helpers4/object';
73
+
74
+ camelCaseKeys<T>(value: T): T
75
+ ```
76
+
77
+ **Parameters:**
78
+
79
+ - `value: T` — The object (or array of objects) to transform
80
+
81
+ **Returns:** `T` — A new value with every plain-object key converted to camelCase
82
+
83
+ **Examples:**
84
+
85
+ *Convert a snake_case API response*
86
+
87
+ Recursively converts every key, including nested objects, to camelCase.
88
+
89
+ ```typescript
90
+ camelCaseKeys({ user_name: 'Alice', home_address: { zip_code: '12345' } })
91
+ // => { userName: 'Alice', homeAddress: { zipCode: '12345' } }
92
+ ```
93
+
94
+ *Arrays of objects are walked too*
95
+
96
+ Each object inside an array gets its keys converted.
97
+
98
+ ```typescript
99
+ camelCaseKeys({ user_list: [{ first_name: 'A' }] })
100
+ // => { userList: [{ firstName: 'A' }] }
101
+ ```
102
+
103
+ ---
104
+
55
105
  ### `clone`
56
106
 
57
107
  Creates a shallow copy of a value — one level deep, unlike cloneDeep.
@@ -675,6 +725,40 @@ function processConfig(config: Record<string, unknown>): void {
675
725
 
676
726
  ---
677
727
 
728
+ ### `kebabCaseKeys`
729
+
730
+ Recursively transforms every key of a plain object (including keys nested inside arrays and
731
+ nested objects) to kebab-case. Handles snake_case, camelCase, PascalCase, and space-separated
732
+ keys. Non-plain-object values — `Date`, `Map`, `Set`, class instances, primitives — are left
733
+ untouched, only their position is walked into. An entry whose transformed key is a
734
+ prototype-polluting string (`__proto__`, `constructor`, `prototype`) is silently skipped,
735
+ same as the rest of `@helpers4/object`.
736
+
737
+ ```typescript
738
+ import { kebabCaseKeys } from '@helpers4/object';
739
+
740
+ kebabCaseKeys<T>(value: T): T
741
+ ```
742
+
743
+ **Parameters:**
744
+
745
+ - `value: T` — The object (or array of objects) to transform
746
+
747
+ **Returns:** `T` — A new value with every plain-object key converted to kebab-case
748
+
749
+ **Examples:**
750
+
751
+ *Convert object keys for a kebab-case config format*
752
+
753
+ Recursively converts every key, including nested objects, to kebab-case.
754
+
755
+ ```typescript
756
+ kebabCaseKeys({ userName: 'Alice', homeAddress: { zipCode: '12345' } })
757
+ // => { 'user-name': 'Alice', 'home-address': { 'zip-code': '12345' } }
758
+ ```
759
+
760
+ ---
761
+
678
762
  ### `map`
679
763
 
680
764
  Transforms the values and/or keys of a plain object in a single pass.
@@ -738,6 +822,70 @@ map(
738
822
 
739
823
  ---
740
824
 
825
+ ### `mapDeep`
826
+
827
+ Recursively transforms the keys and/or values of a plain object — the deep counterpart to
828
+ map, which only transforms the top level. Descends into nested plain objects and
829
+ arrays of them; `Date`, `Map`, `Set`, class instances, and primitives are left untouched
830
+ (only their position is walked into, matching cloneDeep's notion of what counts
831
+ as a plain-data node worth recursing into).
832
+
833
+ Both callbacks are optional and default to identity (no transformation). `mapKey` is called
834
+ with the *original* key and value (before any recursive value transform); `mapValue` receives
835
+ the already-recursed value. Entries whose mapped key is a prototype-polluting string
836
+ (`__proto__`, `constructor`, `prototype`) are silently skipped, same as map.
837
+
838
+ Array elements also go through `mapValue` (with their stringified index as `key`, since
839
+ arrays have no property keys of their own) — so values inside a plain array, not just object
840
+ properties, get transformed too. `mapKey` is never called for array elements, since there is
841
+ no key to rename.
842
+
843
+ ```typescript
844
+ import { mapDeep } from '@helpers4/object';
845
+
846
+ mapDeep<T>(obj: T, mapValue?: function, mapKey?: function): T
847
+ ```
848
+
849
+ **Parameters:**
850
+
851
+ - `obj: T` — The value to transform (typically an object, or an array of objects)
852
+ - `mapValue?: function` — Callback called with `(value, key)` for each entry's (already-recursed) value.
853
+ For array elements, `key` is the element's index as a string. Defaults to identity.
854
+ - `mapKey?: function` — Callback called with `(key, value)` for each object entry. Defaults to identity.
855
+
856
+ **Returns:** `T` — A new value with every plain-object key/value transformed
857
+
858
+ **Examples:**
859
+
860
+ *Transform every key, recursively*
861
+
862
+ Unlike map(), mapDeep() walks into nested objects and arrays of objects.
863
+
864
+ ```typescript
865
+ mapDeep({ a: { b: 1 } }, undefined, key => key.toUpperCase())
866
+ // => { A: { B: 1 } }
867
+ ```
868
+
869
+ *Transform every value, recursively*
870
+
871
+ Values are visited after their own nested content has already been transformed.
872
+
873
+ ```typescript
874
+ mapDeep({ a: { b: 1, c: 2 } }, v => typeof v === 'number' ? v * 10 : v)
875
+ // => { a: { b: 10, c: 20 } }
876
+ ```
877
+
878
+ *Transform values inside arrays too*
879
+
880
+ Array elements are visited by mapValue as well, keyed by their stringified index.
881
+
882
+ ```typescript
883
+ mapDeep({ tags: [1, 2, 3] }, v => typeof v === 'number' ? v * 10 : v)
884
+ // => { tags: [10, 20, 30] }
885
+ ```
886
+
887
+ ---
888
+
741
889
  ### `mergeDeep`
742
890
 
743
891
  Merges two or more objects deeply, returning a **new** object without mutating any input.
@@ -957,6 +1105,40 @@ parsePropertyPath('a[0]b')
957
1105
 
958
1106
  ---
959
1107
 
1108
+ ### `pascalCaseKeys`
1109
+
1110
+ Recursively transforms every key of a plain object (including keys nested inside arrays and
1111
+ nested objects) to PascalCase. Handles camelCase, snake_case, kebab-case, and space-separated
1112
+ keys. Non-plain-object values — `Date`, `Map`, `Set`, class instances, primitives — are left
1113
+ untouched, only their position is walked into. An entry whose transformed key is a
1114
+ prototype-polluting string (`__proto__`, `constructor`, `prototype`) is silently skipped,
1115
+ same as the rest of `@helpers4/object`.
1116
+
1117
+ ```typescript
1118
+ import { pascalCaseKeys } from '@helpers4/object';
1119
+
1120
+ pascalCaseKeys<T>(value: T): T
1121
+ ```
1122
+
1123
+ **Parameters:**
1124
+
1125
+ - `value: T` — The object (or array of objects) to transform
1126
+
1127
+ **Returns:** `T` — A new value with every plain-object key converted to PascalCase
1128
+
1129
+ **Examples:**
1130
+
1131
+ *Convert object keys to PascalCase (e.g. for a C#/JSON.NET consumer)*
1132
+
1133
+ Recursively converts every key, including nested objects, to PascalCase.
1134
+
1135
+ ```typescript
1136
+ pascalCaseKeys({ user_name: 'Alice', home_address: { zip_code: '12345' } })
1137
+ // => { UserName: 'Alice', HomeAddress: { ZipCode: '12345' } }
1138
+ ```
1139
+
1140
+ ---
1141
+
960
1142
  ### `pick`
961
1143
 
962
1144
  Creates a new object with only the specified keys.
@@ -1256,6 +1438,115 @@ set({}, ['user', id], 'alice')
1256
1438
 
1257
1439
  ---
1258
1440
 
1441
+ ### `snakeCaseKeys`
1442
+
1443
+ Recursively transforms every key of a plain object (including keys nested inside arrays and
1444
+ nested objects) to snake_case. Handles camelCase, PascalCase, kebab-case, and space-separated
1445
+ keys. Non-plain-object values — `Date`, `Map`, `Set`, class instances, primitives — are left
1446
+ untouched, only their position is walked into. An entry whose transformed key is a
1447
+ prototype-polluting string (`__proto__`, `constructor`, `prototype`) is silently skipped,
1448
+ same as the rest of `@helpers4/object`.
1449
+
1450
+ ```typescript
1451
+ import { snakeCaseKeys } from '@helpers4/object';
1452
+
1453
+ snakeCaseKeys<T>(value: T): T
1454
+ ```
1455
+
1456
+ **Parameters:**
1457
+
1458
+ - `value: T` — The object (or array of objects) to transform
1459
+
1460
+ **Returns:** `T` — A new value with every plain-object key converted to snake_case
1461
+
1462
+ **Examples:**
1463
+
1464
+ *Convert a camelCase object for a snake_case API*
1465
+
1466
+ Recursively converts every key, including nested objects, to snake_case.
1467
+
1468
+ ```typescript
1469
+ snakeCaseKeys({ userName: 'Alice', homeAddress: { zipCode: '12345' } })
1470
+ // => { user_name: 'Alice', home_address: { zip_code: '12345' } }
1471
+ ```
1472
+
1473
+ ---
1474
+
1475
+ ### `sortKeys`
1476
+
1477
+ Creates a new object with the same entries as the input, but with its own keys sorted.
1478
+ Shallow only — nested objects are copied as-is, their keys are not re-sorted.
1479
+ Key order matters for things like `JSON.stringify` diffs and snapshot stability; this does
1480
+ not change equality (`{a:1,b:2}` and `{b:2,a:1}` are already equal), just iteration/serialization order.
1481
+ Note: integer-index-like keys (`"0"`, `"1"`, `"42"`...) are always iterated first, in numeric
1482
+ order, by the JS engine itself — no object key ordering can override that language behavior.
1483
+ A prototype-polluting key (`__proto__`, `constructor`, `prototype`) is silently skipped,
1484
+ same as the rest of `@helpers4/object`.
1485
+
1486
+ ```typescript
1487
+ import { sortKeys } from '@helpers4/object';
1488
+
1489
+ sortKeys<T extends Record<string, unknown>>(obj: T, compareFn?: function): T
1490
+ ```
1491
+
1492
+ **Parameters:**
1493
+
1494
+ - `obj: T` — The object whose keys to sort
1495
+ - `compareFn?: function` — Optional custom comparator, passed directly to `Array.prototype.sort`
1496
+
1497
+ **Returns:** `T` — A new object with the same entries, own keys in sorted order
1498
+
1499
+ **Examples:**
1500
+
1501
+ *Sort object keys alphabetically*
1502
+
1503
+ Useful for stable JSON.stringify output or predictable snapshot tests.
1504
+
1505
+ ```typescript
1506
+ sortKeys({ b: 2, a: 1, c: 3 })
1507
+ // => { a: 1, b: 2, c: 3 }
1508
+ ```
1509
+
1510
+ ---
1511
+
1512
+ ### `titleCaseKeys`
1513
+
1514
+ Recursively transforms every key of a plain object (including keys nested inside arrays and
1515
+ nested objects) to Title Case. Handles camelCase, snake_case, kebab-case, and space-separated
1516
+ keys. Non-plain-object values — `Date`, `Map`, `Set`, class instances, primitives — are left
1517
+ untouched, only their position is walked into. An entry whose transformed key is a
1518
+ prototype-polluting string (`__proto__`, `constructor`, `prototype`) is silently skipped,
1519
+ same as the rest of `@helpers4/object`.
1520
+
1521
+ Note: unlike the other `*CaseKeys` variants, `titleCase` joins words with spaces (e.g.
1522
+ `'User Name'`) — those keys are only usable via bracket access (`obj['User Name']`), not dot
1523
+ notation. Useful for display-facing structures (form labels, table headers), not wire formats.
1524
+
1525
+ ```typescript
1526
+ import { titleCaseKeys } from '@helpers4/object';
1527
+
1528
+ titleCaseKeys<T>(value: T): T
1529
+ ```
1530
+
1531
+ **Parameters:**
1532
+
1533
+ - `value: T` — The object (or array of objects) to transform
1534
+
1535
+ **Returns:** `T` — A new value with every plain-object key converted to Title Case
1536
+
1537
+ **Examples:**
1538
+
1539
+ *Convert object keys into display-friendly labels*
1540
+
1541
+ Recursively converts every key to Title Case — useful for form labels or table headers.
1542
+
1543
+ ```typescript
1544
+ titleCaseKeys({ user_name: 'Alice', home_address: { zip_code: '12345' } })
1545
+ // => { 'User Name': 'Alice', 'Home Address': { 'Zip Code': '12345' } }
1546
+ ```
1547
+
1548
+ ---
1549
+
1259
1550
  ### `unflatten`
1260
1551
 
1261
1552
  Rebuilds a nested object from a single-level object whose keys are