@fluixi/utils 1.0.0-alpha.53
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/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/dist/lib/array/advanced.cjs +1 -0
- package/dist/lib/array/advanced.d.ts +1116 -0
- package/dist/lib/array/advanced.d.ts.map +1 -0
- package/dist/lib/array/advanced.js +2429 -0
- package/dist/lib/array/advanced.mjs +1 -0
- package/dist/lib/array/array.cjs +1 -0
- package/dist/lib/array/array.d.ts +6 -0
- package/dist/lib/array/array.d.ts.map +1 -0
- package/dist/lib/array/array.js +31 -0
- package/dist/lib/array/array.mjs +1 -0
- package/dist/lib/array/index.cjs +1 -0
- package/dist/lib/array/index.d.ts +4 -0
- package/dist/lib/array/index.d.ts.map +1 -0
- package/dist/lib/array/index.js +3 -0
- package/dist/lib/array/index.mjs +1 -0
- package/dist/lib/array/utils.cjs +1 -0
- package/dist/lib/array/utils.d.ts +100 -0
- package/dist/lib/array/utils.d.ts.map +1 -0
- package/dist/lib/array/utils.js +165 -0
- package/dist/lib/array/utils.mjs +1 -0
- package/dist/lib/color/color.cjs +1 -0
- package/dist/lib/color/color.d.ts +366 -0
- package/dist/lib/color/color.d.ts.map +1 -0
- package/dist/lib/color/color.js +722 -0
- package/dist/lib/color/color.mjs +1 -0
- package/dist/lib/color/constants.cjs +1 -0
- package/dist/lib/color/constants.d.ts +361 -0
- package/dist/lib/color/constants.d.ts.map +1 -0
- package/dist/lib/color/constants.js +358 -0
- package/dist/lib/color/constants.mjs +1 -0
- package/dist/lib/color/conversions.cjs +1 -0
- package/dist/lib/color/conversions.d.ts +166 -0
- package/dist/lib/color/conversions.d.ts.map +1 -0
- package/dist/lib/color/conversions.js +766 -0
- package/dist/lib/color/conversions.mjs +1 -0
- package/dist/lib/color/helpers.cjs +1 -0
- package/dist/lib/color/helpers.d.ts +75 -0
- package/dist/lib/color/helpers.d.ts.map +1 -0
- package/dist/lib/color/helpers.js +419 -0
- package/dist/lib/color/helpers.mjs +1 -0
- package/dist/lib/color/index.cjs +1 -0
- package/dist/lib/color/index.d.ts +12 -0
- package/dist/lib/color/index.d.ts.map +1 -0
- package/dist/lib/color/index.js +15 -0
- package/dist/lib/color/index.mjs +1 -0
- package/dist/lib/color/types.cjs +1 -0
- package/dist/lib/color/types.d.ts +179 -0
- package/dist/lib/color/types.d.ts.map +1 -0
- package/dist/lib/color/types.js +1 -0
- package/dist/lib/color/types.mjs +0 -0
- package/dist/lib/color/utils.cjs +1 -0
- package/dist/lib/color/utils.d.ts +199 -0
- package/dist/lib/color/utils.d.ts.map +1 -0
- package/dist/lib/color/utils.js +858 -0
- package/dist/lib/color/utils.mjs +1 -0
- package/dist/lib/compare/comparators.cjs +1 -0
- package/dist/lib/compare/comparators.d.ts +65 -0
- package/dist/lib/compare/comparators.d.ts.map +1 -0
- package/dist/lib/compare/comparators.js +210 -0
- package/dist/lib/compare/comparators.mjs +1 -0
- package/dist/lib/compare/index.cjs +1 -0
- package/dist/lib/compare/index.d.ts +2 -0
- package/dist/lib/compare/index.d.ts.map +1 -0
- package/dist/lib/compare/index.js +1 -0
- package/dist/lib/compare/index.mjs +1 -0
- package/dist/lib/crypto/hash.cjs +1 -0
- package/dist/lib/crypto/hash.d.ts +6 -0
- package/dist/lib/crypto/hash.d.ts.map +1 -0
- package/dist/lib/crypto/hash.js +53 -0
- package/dist/lib/crypto/hash.mjs +1 -0
- package/dist/lib/crypto/index.cjs +1 -0
- package/dist/lib/crypto/index.d.ts +2 -0
- package/dist/lib/crypto/index.d.ts.map +1 -0
- package/dist/lib/crypto/index.js +1 -0
- package/dist/lib/crypto/index.mjs +1 -0
- package/dist/lib/dom/events.cjs +1 -0
- package/dist/lib/dom/events.d.ts +159 -0
- package/dist/lib/dom/events.d.ts.map +1 -0
- package/dist/lib/dom/events.js +50 -0
- package/dist/lib/dom/events.mjs +1 -0
- package/dist/lib/dom/index.cjs +1 -0
- package/dist/lib/dom/index.d.ts +3 -0
- package/dist/lib/dom/index.d.ts.map +1 -0
- package/dist/lib/dom/index.js +2 -0
- package/dist/lib/dom/index.mjs +1 -0
- package/dist/lib/dom/utils.cjs +1 -0
- package/dist/lib/dom/utils.d.ts +6 -0
- package/dist/lib/dom/utils.d.ts.map +1 -0
- package/dist/lib/dom/utils.js +37 -0
- package/dist/lib/dom/utils.mjs +1 -0
- package/dist/lib/functions/functions.cjs +1 -0
- package/dist/lib/functions/functions.d.ts +329 -0
- package/dist/lib/functions/functions.d.ts.map +1 -0
- package/dist/lib/functions/functions.js +585 -0
- package/dist/lib/functions/functions.mjs +1 -0
- package/dist/lib/functions/index.cjs +1 -0
- package/dist/lib/functions/index.d.ts +3 -0
- package/dist/lib/functions/index.d.ts.map +1 -0
- package/dist/lib/functions/index.js +1 -0
- package/dist/lib/functions/index.mjs +1 -0
- package/dist/lib/functions/types.cjs +1 -0
- package/dist/lib/functions/types.d.ts +2 -0
- package/dist/lib/functions/types.d.ts.map +1 -0
- package/dist/lib/functions/types.js +1 -0
- package/dist/lib/functions/types.mjs +0 -0
- package/dist/lib/helpers.cjs +1 -0
- package/dist/lib/helpers.d.ts +13 -0
- package/dist/lib/helpers.d.ts.map +1 -0
- package/dist/lib/helpers.js +66 -0
- package/dist/lib/helpers.mjs +1 -0
- package/dist/lib/index.cjs +1 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +8 -0
- package/dist/lib/index.mjs +1 -0
- package/dist/lib/maths/constants.cjs +1 -0
- package/dist/lib/maths/constants.d.ts +84 -0
- package/dist/lib/maths/constants.d.ts.map +1 -0
- package/dist/lib/maths/constants.js +79 -0
- package/dist/lib/maths/constants.mjs +1 -0
- package/dist/lib/maths/fn/advanced.cjs +1 -0
- package/dist/lib/maths/fn/advanced.d.ts +149 -0
- package/dist/lib/maths/fn/advanced.d.ts.map +1 -0
- package/dist/lib/maths/fn/advanced.js +264 -0
- package/dist/lib/maths/fn/advanced.mjs +1 -0
- package/dist/lib/maths/fn/basic.cjs +1 -0
- package/dist/lib/maths/fn/basic.d.ts +182 -0
- package/dist/lib/maths/fn/basic.d.ts.map +1 -0
- package/dist/lib/maths/fn/basic.js +343 -0
- package/dist/lib/maths/fn/basic.mjs +1 -0
- package/dist/lib/maths/fn/complex.cjs +1 -0
- package/dist/lib/maths/fn/complex.d.ts +153 -0
- package/dist/lib/maths/fn/complex.d.ts.map +1 -0
- package/dist/lib/maths/fn/complex.js +383 -0
- package/dist/lib/maths/fn/complex.mjs +1 -0
- package/dist/lib/maths/fn/index.cjs +1 -0
- package/dist/lib/maths/fn/index.d.ts +10 -0
- package/dist/lib/maths/fn/index.d.ts.map +1 -0
- package/dist/lib/maths/fn/index.js +9 -0
- package/dist/lib/maths/fn/index.mjs +1 -0
- package/dist/lib/maths/fn/trigo.cjs +1 -0
- package/dist/lib/maths/fn/trigo.d.ts +147 -0
- package/dist/lib/maths/fn/trigo.d.ts.map +1 -0
- package/dist/lib/maths/fn/trigo.js +227 -0
- package/dist/lib/maths/fn/trigo.mjs +1 -0
- package/dist/lib/maths/fn/vector.cjs +1 -0
- package/dist/lib/maths/fn/vector.d.ts +512 -0
- package/dist/lib/maths/fn/vector.d.ts.map +1 -0
- package/dist/lib/maths/fn/vector.js +1136 -0
- package/dist/lib/maths/fn/vector.mjs +1 -0
- package/dist/lib/maths/formatter.cjs +1 -0
- package/dist/lib/maths/formatter.d.ts +35 -0
- package/dist/lib/maths/formatter.d.ts.map +1 -0
- package/dist/lib/maths/formatter.js +56 -0
- package/dist/lib/maths/formatter.mjs +1 -0
- package/dist/lib/maths/guards.cjs +1 -0
- package/dist/lib/maths/guards.d.ts +166 -0
- package/dist/lib/maths/guards.d.ts.map +1 -0
- package/dist/lib/maths/guards.js +315 -0
- package/dist/lib/maths/guards.mjs +1 -0
- package/dist/lib/maths/index.cjs +1 -0
- package/dist/lib/maths/index.d.ts +24 -0
- package/dist/lib/maths/index.d.ts.map +1 -0
- package/dist/lib/maths/index.js +29 -0
- package/dist/lib/maths/index.mjs +1 -0
- package/dist/lib/maths/parser.cjs +1 -0
- package/dist/lib/maths/parser.d.ts +20 -0
- package/dist/lib/maths/parser.d.ts.map +1 -0
- package/dist/lib/maths/parser.js +78 -0
- package/dist/lib/maths/parser.mjs +1 -0
- package/dist/lib/maths/random.cjs +1 -0
- package/dist/lib/maths/random.d.ts +27 -0
- package/dist/lib/maths/random.d.ts.map +1 -0
- package/dist/lib/maths/random.js +49 -0
- package/dist/lib/maths/random.mjs +1 -0
- package/dist/lib/maths/types/advanced.cjs +1 -0
- package/dist/lib/maths/types/advanced.d.ts +357 -0
- package/dist/lib/maths/types/advanced.d.ts.map +1 -0
- package/dist/lib/maths/types/advanced.js +5 -0
- package/dist/lib/maths/types/advanced.mjs +0 -0
- package/dist/lib/maths/types/basic.cjs +1 -0
- package/dist/lib/maths/types/basic.d.ts +95 -0
- package/dist/lib/maths/types/basic.d.ts.map +1 -0
- package/dist/lib/maths/types/basic.js +5 -0
- package/dist/lib/maths/types/basic.mjs +0 -0
- package/dist/lib/maths/types/index.cjs +1 -0
- package/dist/lib/maths/types/index.d.ts +4 -0
- package/dist/lib/maths/types/index.d.ts.map +1 -0
- package/dist/lib/maths/types/index.js +3 -0
- package/dist/lib/maths/types/index.mjs +0 -0
- package/dist/lib/maths/types/negative.cjs +1 -0
- package/dist/lib/maths/types/negative.d.ts +51 -0
- package/dist/lib/maths/types/negative.d.ts.map +1 -0
- package/dist/lib/maths/types/negative.js +5 -0
- package/dist/lib/maths/types/negative.mjs +0 -0
- package/dist/lib/maths/types/operations.cjs +1 -0
- package/dist/lib/maths/types/operations.d.ts +188 -0
- package/dist/lib/maths/types/operations.d.ts.map +1 -0
- package/dist/lib/maths/types/operations.js +6 -0
- package/dist/lib/maths/types/operations.mjs +0 -0
- package/dist/lib/object/clone.cjs +1 -0
- package/dist/lib/object/clone.d.ts +46 -0
- package/dist/lib/object/clone.d.ts.map +1 -0
- package/dist/lib/object/clone.js +104 -0
- package/dist/lib/object/clone.mjs +1 -0
- package/dist/lib/object/diff.cjs +1 -0
- package/dist/lib/object/diff.d.ts +203 -0
- package/dist/lib/object/diff.d.ts.map +1 -0
- package/dist/lib/object/diff.js +805 -0
- package/dist/lib/object/diff.mjs +1 -0
- package/dist/lib/object/getter-setter.cjs +1 -0
- package/dist/lib/object/getter-setter.d.ts +361 -0
- package/dist/lib/object/getter-setter.d.ts.map +1 -0
- package/dist/lib/object/getter-setter.js +1771 -0
- package/dist/lib/object/getter-setter.mjs +1 -0
- package/dist/lib/object/index.cjs +6 -0
- package/dist/lib/object/index.d.ts +13 -0
- package/dist/lib/object/index.d.ts.map +1 -0
- package/dist/lib/object/index.js +12 -0
- package/dist/lib/object/index.mjs +6 -0
- package/dist/lib/object/merge.cjs +1 -0
- package/dist/lib/object/merge.d.ts +93 -0
- package/dist/lib/object/merge.d.ts.map +1 -0
- package/dist/lib/object/merge.js +474 -0
- package/dist/lib/object/merge.mjs +1 -0
- package/dist/lib/object/object.cjs +1 -0
- package/dist/lib/object/object.d.ts +128 -0
- package/dist/lib/object/object.d.ts.map +1 -0
- package/dist/lib/object/object.js +432 -0
- package/dist/lib/object/object.mjs +1 -0
- package/dist/lib/object/omit.cjs +1 -0
- package/dist/lib/object/omit.d.ts +351 -0
- package/dist/lib/object/omit.d.ts.map +1 -0
- package/dist/lib/object/omit.js +656 -0
- package/dist/lib/object/omit.mjs +1 -0
- package/dist/lib/object/reconcile.cjs +1 -0
- package/dist/lib/object/reconcile.d.ts +7 -0
- package/dist/lib/object/reconcile.d.ts.map +1 -0
- package/dist/lib/object/reconcile.js +122 -0
- package/dist/lib/object/reconcile.mjs +1 -0
- package/dist/lib/object/selector.cjs +1 -0
- package/dist/lib/object/selector.d.ts +50 -0
- package/dist/lib/object/selector.d.ts.map +1 -0
- package/dist/lib/object/selector.js +371 -0
- package/dist/lib/object/selector.mjs +1 -0
- package/dist/lib/object/sort.cjs +1 -0
- package/dist/lib/object/sort.d.ts +149 -0
- package/dist/lib/object/sort.d.ts.map +1 -0
- package/dist/lib/object/sort.js +298 -0
- package/dist/lib/object/sort.mjs +1 -0
- package/dist/lib/object/transform.cjs +1 -0
- package/dist/lib/object/transform.d.ts +620 -0
- package/dist/lib/object/transform.d.ts.map +1 -0
- package/dist/lib/object/transform.js +1058 -0
- package/dist/lib/object/transform.mjs +1 -0
- package/dist/lib/object/types.cjs +1 -0
- package/dist/lib/object/types.d.ts +250 -0
- package/dist/lib/object/types.d.ts.map +1 -0
- package/dist/lib/object/types.js +1 -0
- package/dist/lib/object/types.mjs +0 -0
- package/dist/lib/object/utils.cjs +6 -0
- package/dist/lib/object/utils.d.ts +165 -0
- package/dist/lib/object/utils.d.ts.map +1 -0
- package/dist/lib/object/utils.js +444 -0
- package/dist/lib/object/utils.mjs +6 -0
- package/dist/lib/primitive/boolean/boolean.cjs +1 -0
- package/dist/lib/primitive/boolean/boolean.d.ts +276 -0
- package/dist/lib/primitive/boolean/boolean.d.ts.map +1 -0
- package/dist/lib/primitive/boolean/boolean.js +615 -0
- package/dist/lib/primitive/boolean/boolean.mjs +1 -0
- package/dist/lib/primitive/boolean/index.cjs +1 -0
- package/dist/lib/primitive/boolean/index.d.ts +3 -0
- package/dist/lib/primitive/boolean/index.d.ts.map +1 -0
- package/dist/lib/primitive/boolean/index.js +2 -0
- package/dist/lib/primitive/boolean/index.mjs +1 -0
- package/dist/lib/primitive/boolean/types.cjs +1 -0
- package/dist/lib/primitive/boolean/types.d.ts +14 -0
- package/dist/lib/primitive/boolean/types.d.ts.map +1 -0
- package/dist/lib/primitive/boolean/types.js +1 -0
- package/dist/lib/primitive/boolean/types.mjs +0 -0
- package/dist/lib/primitive/date/date.cjs +1 -0
- package/dist/lib/primitive/date/date.d.ts +641 -0
- package/dist/lib/primitive/date/date.d.ts.map +1 -0
- package/dist/lib/primitive/date/date.js +1998 -0
- package/dist/lib/primitive/date/date.mjs +1 -0
- package/dist/lib/primitive/date/index.cjs +1 -0
- package/dist/lib/primitive/date/index.d.ts +3 -0
- package/dist/lib/primitive/date/index.d.ts.map +1 -0
- package/dist/lib/primitive/date/index.js +2 -0
- package/dist/lib/primitive/date/index.mjs +1 -0
- package/dist/lib/primitive/date/types.cjs +1 -0
- package/dist/lib/primitive/date/types.d.ts +205 -0
- package/dist/lib/primitive/date/types.d.ts.map +1 -0
- package/dist/lib/primitive/date/types.js +7 -0
- package/dist/lib/primitive/date/types.mjs +0 -0
- package/dist/lib/primitive/index.cjs +5 -0
- package/dist/lib/primitive/index.d.ts +5 -0
- package/dist/lib/primitive/index.d.ts.map +1 -0
- package/dist/lib/primitive/index.js +4 -0
- package/dist/lib/primitive/index.mjs +5 -0
- package/dist/lib/primitive/string/index.cjs +5 -0
- package/dist/lib/primitive/string/index.d.ts +3 -0
- package/dist/lib/primitive/string/index.d.ts.map +1 -0
- package/dist/lib/primitive/string/index.js +2 -0
- package/dist/lib/primitive/string/index.mjs +5 -0
- package/dist/lib/primitive/string/parser-2.cjs +8 -0
- package/dist/lib/primitive/string/parser-2.d.ts +17 -0
- package/dist/lib/primitive/string/parser-2.d.ts.map +1 -0
- package/dist/lib/primitive/string/parser-2.js +656 -0
- package/dist/lib/primitive/string/parser-2.mjs +8 -0
- package/dist/lib/primitive/string/parser.cjs +3 -0
- package/dist/lib/primitive/string/parser.d.ts +9 -0
- package/dist/lib/primitive/string/parser.d.ts.map +1 -0
- package/dist/lib/primitive/string/parser.js +775 -0
- package/dist/lib/primitive/string/parser.mjs +3 -0
- package/dist/lib/primitive/string/string.cjs +5 -0
- package/dist/lib/primitive/string/string.d.ts +535 -0
- package/dist/lib/primitive/string/string.d.ts.map +1 -0
- package/dist/lib/primitive/string/string.js +1301 -0
- package/dist/lib/primitive/string/string.mjs +5 -0
- package/dist/lib/primitive/string/types.cjs +1 -0
- package/dist/lib/primitive/string/types.d.ts +318 -0
- package/dist/lib/primitive/string/types.d.ts.map +1 -0
- package/dist/lib/primitive/string/types.js +5 -0
- package/dist/lib/primitive/string/types.mjs +0 -0
- package/dist/lib/primitive/types.cjs +1 -0
- package/dist/lib/primitive/types.d.ts +27 -0
- package/dist/lib/primitive/types.d.ts.map +1 -0
- package/dist/lib/primitive/types.js +1 -0
- package/dist/lib/primitive/types.mjs +0 -0
- package/dist/lib/url/index.cjs +1 -0
- package/dist/lib/url/index.d.ts +3 -0
- package/dist/lib/url/index.d.ts.map +1 -0
- package/dist/lib/url/index.js +2 -0
- package/dist/lib/url/index.mjs +1 -0
- package/dist/lib/url/parser.cjs +1 -0
- package/dist/lib/url/parser.d.ts +216 -0
- package/dist/lib/url/parser.d.ts.map +1 -0
- package/dist/lib/url/parser.js +488 -0
- package/dist/lib/url/parser.mjs +1 -0
- package/dist/lib/url/types.cjs +1 -0
- package/dist/lib/url/types.d.ts +18 -0
- package/dist/lib/url/types.d.ts.map +1 -0
- package/dist/lib/url/types.js +1 -0
- package/dist/lib/url/types.mjs +0 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/package.json +150 -0
|
@@ -0,0 +1,1058 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Object transformation utilities for restructuring, mapping, and applying transformations.
|
|
3
|
+
* @module transform
|
|
4
|
+
*/
|
|
5
|
+
import { isObject } from './utils.js';
|
|
6
|
+
import { get, set } from './getter-setter.js';
|
|
7
|
+
import { parseSelector } from './selector.js';
|
|
8
|
+
/**
|
|
9
|
+
* Maps object values with a transform function, keeping the same keys
|
|
10
|
+
*
|
|
11
|
+
* Creates a new object with the same keys as the input, but with transformed values
|
|
12
|
+
* using the provided function. The function receives the value, key, and original object.
|
|
13
|
+
*
|
|
14
|
+
* @template T - The input object type
|
|
15
|
+
* @template R - The transformed value type
|
|
16
|
+
* @param obj - The source object
|
|
17
|
+
* @param fn - The transform function to apply to each value
|
|
18
|
+
* @returns A new object with transformed values
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const prices = { apple: '1.25', banana: '0.75', orange: '1.00' };
|
|
23
|
+
* const numericPrices = mapValues(prices, price => parseFloat(price));
|
|
24
|
+
* // { apple: 1.25, banana: 0.75, orange: 1 }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function mapValues(obj, fn) {
|
|
28
|
+
if (!isObject(obj)) {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
const result = {};
|
|
32
|
+
for (const key in obj) {
|
|
33
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
34
|
+
result[key] = fn(obj[key], key, obj);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Maps object keys with a transform function, keeping the same values
|
|
41
|
+
*
|
|
42
|
+
* Creates a new object with transformed keys using the provided function,
|
|
43
|
+
* while maintaining the original values. The function receives the key, value, and original object.
|
|
44
|
+
*
|
|
45
|
+
* @template T - The input object type
|
|
46
|
+
* @param obj - The source object
|
|
47
|
+
* @param fn - The transform function to apply to each key
|
|
48
|
+
* @returns A new object with transformed keys
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* const data = { firstName: 'Alice', lastName: 'Smith' };
|
|
53
|
+
* const camelToSnake = mapKeys(data, key => key.replace(/[A-Z]/g, c => `_${c.toLowerCase()}`));
|
|
54
|
+
* // { first_name: 'Alice', last_name: 'Smith' }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function mapKeys(obj, fn) {
|
|
58
|
+
if (!isObject(obj)) {
|
|
59
|
+
return {};
|
|
60
|
+
}
|
|
61
|
+
const result = {};
|
|
62
|
+
for (const key in obj) {
|
|
63
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
64
|
+
const newKey = fn(key, obj[key], obj);
|
|
65
|
+
result[newKey] = obj[key];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Transforms keys to camelCase
|
|
72
|
+
*
|
|
73
|
+
* Creates a new object with all keys transformed to camelCase format.
|
|
74
|
+
* Handles keys in kebab-case, snake_case, and PascalCase.
|
|
75
|
+
*
|
|
76
|
+
* @template T - The input object type
|
|
77
|
+
* @param obj - The source object
|
|
78
|
+
* @param options - Transformation options
|
|
79
|
+
* @param options.deep - Whether to transform nested objects (default: true)
|
|
80
|
+
* @returns A new object with camelCase keys
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* const data = {
|
|
85
|
+
* first_name: 'Alice',
|
|
86
|
+
* 'last-name': 'Smith',
|
|
87
|
+
* ContactInfo: {
|
|
88
|
+
* email_address: 'alice@example.com',
|
|
89
|
+
* phone_number: '555-1234'
|
|
90
|
+
* }
|
|
91
|
+
* };
|
|
92
|
+
*
|
|
93
|
+
* const camelCased = camelCaseKeys(data);
|
|
94
|
+
* // {
|
|
95
|
+
* // firstName: 'Alice',
|
|
96
|
+
* // lastName: 'Smith',
|
|
97
|
+
* // contactInfo: {
|
|
98
|
+
* // emailAddress: 'alice@example.com',
|
|
99
|
+
* // phoneNumber: '555-1234'
|
|
100
|
+
* // }
|
|
101
|
+
* // }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export function camelCaseKeys(obj, options = { deep: true }) {
|
|
105
|
+
if (!isObject(obj)) {
|
|
106
|
+
return obj;
|
|
107
|
+
}
|
|
108
|
+
if (Array.isArray(obj)) {
|
|
109
|
+
return (options.deep ? obj.map((item) => camelCaseKeys(item, options)) : obj);
|
|
110
|
+
}
|
|
111
|
+
const result = {};
|
|
112
|
+
for (const key in obj) {
|
|
113
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
114
|
+
const value = obj[key];
|
|
115
|
+
const camelKey = key
|
|
116
|
+
.replace(/[-_]([a-z])/g, (_, c) => c.toUpperCase())
|
|
117
|
+
.replace(/^([A-Z])/, (c) => c.toLowerCase());
|
|
118
|
+
result[camelKey] =
|
|
119
|
+
options.deep && isObject(value) ? camelCaseKeys(value, options) : value;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Transforms keys to snake_case
|
|
126
|
+
*
|
|
127
|
+
* Creates a new object with all keys transformed to snake_case format.
|
|
128
|
+
* Handles keys in camelCase, kebab-case, and PascalCase.
|
|
129
|
+
*
|
|
130
|
+
* @template T - The input object type
|
|
131
|
+
* @param obj - The source object
|
|
132
|
+
* @param options - Transformation options
|
|
133
|
+
* @param options.deep - Whether to transform nested objects (default: true)
|
|
134
|
+
* @returns A new object with snake_case keys
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* const data = {
|
|
139
|
+
* firstName: 'Alice',
|
|
140
|
+
* 'last-name': 'Smith',
|
|
141
|
+
* ContactInfo: {
|
|
142
|
+
* emailAddress: 'alice@example.com',
|
|
143
|
+
* phoneNumber: '555-1234'
|
|
144
|
+
* }
|
|
145
|
+
* };
|
|
146
|
+
*
|
|
147
|
+
* const snakeCased = snakeCaseKeys(data);
|
|
148
|
+
* // {
|
|
149
|
+
* // first_name: 'Alice',
|
|
150
|
+
* // last_name: 'Smith',
|
|
151
|
+
* // contact_info: {
|
|
152
|
+
* // email_address: 'alice@example.com',
|
|
153
|
+
* // phone_number: '555-1234'
|
|
154
|
+
* // }
|
|
155
|
+
* // }
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export function snakeCaseKeys(obj, options = { deep: true }) {
|
|
159
|
+
if (!isObject(obj)) {
|
|
160
|
+
return obj;
|
|
161
|
+
}
|
|
162
|
+
if (Array.isArray(obj)) {
|
|
163
|
+
return (options.deep ? obj.map((item) => snakeCaseKeys(item, options)) : obj);
|
|
164
|
+
}
|
|
165
|
+
const result = {};
|
|
166
|
+
for (const key in obj) {
|
|
167
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
168
|
+
const value = obj[key];
|
|
169
|
+
const snakeKey = key
|
|
170
|
+
.replace(/[-]([a-z])/g, (_, c) => `_${c}`)
|
|
171
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
172
|
+
.toLowerCase();
|
|
173
|
+
result[snakeKey] =
|
|
174
|
+
options.deep && isObject(value) ? snakeCaseKeys(value, options) : value;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Transforms keys to kebab-case
|
|
181
|
+
*
|
|
182
|
+
* Creates a new object with all keys transformed to kebab-case format.
|
|
183
|
+
* Handles keys in camelCase, snake_case, and PascalCase.
|
|
184
|
+
*
|
|
185
|
+
* @template T - The input object type
|
|
186
|
+
* @param obj - The source object
|
|
187
|
+
* @param options - Transformation options
|
|
188
|
+
* @param options.deep - Whether to transform nested objects (default: true)
|
|
189
|
+
* @returns A new object with kebab-case keys
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```ts
|
|
193
|
+
* const data = {
|
|
194
|
+
* firstName: 'Alice',
|
|
195
|
+
* last_name: 'Smith',
|
|
196
|
+
* ContactInfo: {
|
|
197
|
+
* emailAddress: 'alice@example.com',
|
|
198
|
+
* phone_number: '555-1234'
|
|
199
|
+
* }
|
|
200
|
+
* };
|
|
201
|
+
*
|
|
202
|
+
* const kebabCased = kebabCaseKeys(data);
|
|
203
|
+
* // {
|
|
204
|
+
* // 'first-name': 'Alice',
|
|
205
|
+
* // 'last-name': 'Smith',
|
|
206
|
+
* // 'contact-info': {
|
|
207
|
+
* // 'email-address': 'alice@example.com',
|
|
208
|
+
* // 'phone-number': '555-1234'
|
|
209
|
+
* // }
|
|
210
|
+
* // }
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
export function kebabCaseKeys(obj, options = { deep: true }) {
|
|
214
|
+
if (!isObject(obj)) {
|
|
215
|
+
return obj;
|
|
216
|
+
}
|
|
217
|
+
if (Array.isArray(obj)) {
|
|
218
|
+
return (options.deep ? obj.map((item) => kebabCaseKeys(item, options)) : obj);
|
|
219
|
+
}
|
|
220
|
+
const result = {};
|
|
221
|
+
for (const key in obj) {
|
|
222
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
223
|
+
const value = obj[key];
|
|
224
|
+
const kebabKey = key
|
|
225
|
+
.replace(/[_]([a-z])/g, (_, c) => `-${c}`)
|
|
226
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
227
|
+
.toLowerCase();
|
|
228
|
+
result[kebabKey] =
|
|
229
|
+
options.deep && isObject(value) ? kebabCaseKeys(value, options) : value;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Flattens a nested object structure into a single-level object with path-based keys
|
|
236
|
+
*
|
|
237
|
+
* Creates a new flat object where nested keys are represented as path strings.
|
|
238
|
+
* Supports custom path delimiters and array handling.
|
|
239
|
+
*
|
|
240
|
+
* @template T - The input object type
|
|
241
|
+
* @param obj - The source object to flatten
|
|
242
|
+
* @param options - Flattening options
|
|
243
|
+
* @param options.delimiter - Character(s) to separate path segments (default: '.')
|
|
244
|
+
* @param options.includeArrays - Whether to flatten arrays (default: true)
|
|
245
|
+
* @param options.maxDepth - Maximum depth to flatten (default: Infinity)
|
|
246
|
+
* @returns A flattened object with path keys
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```ts
|
|
250
|
+
* const user = {
|
|
251
|
+
* name: {
|
|
252
|
+
* first: 'Alice',
|
|
253
|
+
* last: 'Smith'
|
|
254
|
+
* },
|
|
255
|
+
* contacts: [
|
|
256
|
+
* { type: 'email', value: 'alice@example.com' },
|
|
257
|
+
* { type: 'phone', value: '555-1234' }
|
|
258
|
+
* ]
|
|
259
|
+
* };
|
|
260
|
+
*
|
|
261
|
+
* const flattened = flatten(user);
|
|
262
|
+
* // {
|
|
263
|
+
* // 'name.first': 'Alice',
|
|
264
|
+
* // 'name.last': 'Smith',
|
|
265
|
+
* // 'contacts.0.type': 'email',
|
|
266
|
+
* // 'contacts.0.value': 'alice@example.com',
|
|
267
|
+
* // 'contacts.1.type': 'phone',
|
|
268
|
+
* // 'contacts.1.value': '555-1234'
|
|
269
|
+
* // }
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
// export function flatten<T extends AnyObject>(
|
|
273
|
+
// obj: T,
|
|
274
|
+
// options: {
|
|
275
|
+
// delimiter?: string;
|
|
276
|
+
// includeArrays?: boolean;
|
|
277
|
+
// maxDepth?: number;
|
|
278
|
+
// } = {}
|
|
279
|
+
// ): Record<string, any> {
|
|
280
|
+
// const {
|
|
281
|
+
// delimiter = '.',
|
|
282
|
+
// includeArrays = true,
|
|
283
|
+
// maxDepth = Infinity,
|
|
284
|
+
// } = options;
|
|
285
|
+
// const result: Record<string, any> = {};
|
|
286
|
+
// function _flatten(current: any, path: string = '', depth: number = 0) {
|
|
287
|
+
// if (depth > maxDepth) {
|
|
288
|
+
// result[path] = current;
|
|
289
|
+
// return;
|
|
290
|
+
// }
|
|
291
|
+
// if (!isObject(current)) {
|
|
292
|
+
// result[path] = current;
|
|
293
|
+
// return;
|
|
294
|
+
// }
|
|
295
|
+
// if (Array.isArray(current) && !includeArrays) {
|
|
296
|
+
// result[path] = current;
|
|
297
|
+
// return;
|
|
298
|
+
// }
|
|
299
|
+
// if (Object.keys(current).length === 0) {
|
|
300
|
+
// result[path] = current;
|
|
301
|
+
// return;
|
|
302
|
+
// }
|
|
303
|
+
// const prefix = path ? `${path}${delimiter}` : '';
|
|
304
|
+
// if (Array.isArray(current)) {
|
|
305
|
+
// for (let i = 0; i < current.length; i++) {
|
|
306
|
+
// _flatten(current[i], `${prefix}${i}`, depth + 1);
|
|
307
|
+
// }
|
|
308
|
+
// return;
|
|
309
|
+
// }
|
|
310
|
+
// for (const key in current) {
|
|
311
|
+
// if (Object.prototype.hasOwnProperty.call(current, key)) {
|
|
312
|
+
// _flatten(current[key], `${prefix}${key}`, depth + 1);
|
|
313
|
+
// }
|
|
314
|
+
// }
|
|
315
|
+
// }
|
|
316
|
+
// _flatten(obj);
|
|
317
|
+
// return result;
|
|
318
|
+
// }
|
|
319
|
+
export const flatten = (obj, options = {}) => {
|
|
320
|
+
const { delimiter = '.', includeArrays = false, maxDepth = 9 } = options;
|
|
321
|
+
if (Array.isArray(obj)) {
|
|
322
|
+
return obj.map((item) => flatten(item, options));
|
|
323
|
+
// return obj.reduce((acc, item) => {
|
|
324
|
+
// return {
|
|
325
|
+
// ...acc,
|
|
326
|
+
// ...flatten(item, separator),
|
|
327
|
+
// };
|
|
328
|
+
// }, {});
|
|
329
|
+
}
|
|
330
|
+
const result = {};
|
|
331
|
+
const flattenRecursive = (current, path = '', depth = 0) => {
|
|
332
|
+
if (depth > maxDepth) {
|
|
333
|
+
result[path] = current;
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (!isObject(current) && !Array.isArray(current)) {
|
|
337
|
+
if (path) {
|
|
338
|
+
result[path] = current;
|
|
339
|
+
}
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (Array.isArray(current)) {
|
|
343
|
+
for (let i = 0; i < current.length; i++) {
|
|
344
|
+
const newPath = path ? `${path}[${i}]` : `[${i}]`;
|
|
345
|
+
flattenRecursive(current[i], newPath, depth + 1);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
for (const key in current) {
|
|
350
|
+
const newPath = path ? `${path}${delimiter}${key}` : key;
|
|
351
|
+
flattenRecursive(current[key], newPath, depth + 1);
|
|
352
|
+
}
|
|
353
|
+
// Handle symbols
|
|
354
|
+
const symbols = Object.getOwnPropertySymbols(current);
|
|
355
|
+
for (const symbol of symbols) {
|
|
356
|
+
const newPath = path
|
|
357
|
+
? `${path}${delimiter}${symbol.toString()}`
|
|
358
|
+
: symbol.toString();
|
|
359
|
+
flattenRecursive(current[symbol], newPath, depth + 1);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
flattenRecursive(obj);
|
|
364
|
+
return result;
|
|
365
|
+
};
|
|
366
|
+
/**
|
|
367
|
+
* Unflatten a single-level object with path-based keys into a nested object structure
|
|
368
|
+
*
|
|
369
|
+
* Reverses the flattening process, converting an object with path keys back into a nested structure.
|
|
370
|
+
* Supports custom path delimiters and array detection.
|
|
371
|
+
*
|
|
372
|
+
* @param obj - The flattened object to unflatten
|
|
373
|
+
* @param options - Unflattening options
|
|
374
|
+
* @param options.delimiter - Character(s) that separate path segments (default: '.')
|
|
375
|
+
* @param options.detectArrays - Whether to convert numeric indices to arrays (default: true)
|
|
376
|
+
* @returns A nested object structure
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```ts
|
|
380
|
+
* const flattened = {
|
|
381
|
+
* 'user.name.first': 'Alice',
|
|
382
|
+
* 'user.name.last': 'Smith',
|
|
383
|
+
* 'user.contacts.0.type': 'email',
|
|
384
|
+
* 'user.contacts.0.value': 'alice@example.com',
|
|
385
|
+
* 'user.contacts.1.type': 'phone',
|
|
386
|
+
* 'user.contacts.1.value': '555-1234'
|
|
387
|
+
* };
|
|
388
|
+
*
|
|
389
|
+
* const nested = unflatten(flattened);
|
|
390
|
+
* // {
|
|
391
|
+
* // user: {
|
|
392
|
+
* // name: {
|
|
393
|
+
* // first: 'Alice',
|
|
394
|
+
* // last: 'Smith'
|
|
395
|
+
* // },
|
|
396
|
+
* // contacts: [
|
|
397
|
+
* // { type: 'email', value: 'alice@example.com' },
|
|
398
|
+
* // { type: 'phone', value: '555-1234' }
|
|
399
|
+
* // ]
|
|
400
|
+
* // }
|
|
401
|
+
* // }
|
|
402
|
+
* ```
|
|
403
|
+
*/
|
|
404
|
+
export function unflatten(obj, options = {}) {
|
|
405
|
+
const { delimiter = '.', detectArrays = true } = options;
|
|
406
|
+
const result = {};
|
|
407
|
+
for (const key in obj) {
|
|
408
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
409
|
+
const value = obj[key];
|
|
410
|
+
const parts = key.split(delimiter);
|
|
411
|
+
let current = result;
|
|
412
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
413
|
+
const part = parts[i];
|
|
414
|
+
const nextPart = parts[i + 1];
|
|
415
|
+
const isNextPartArrayIndex = detectArrays && /^\d+$/.test(nextPart);
|
|
416
|
+
if (!(part in current)) {
|
|
417
|
+
current[part] = isNextPartArrayIndex ? [] : {};
|
|
418
|
+
}
|
|
419
|
+
else if (isNextPartArrayIndex && !Array.isArray(current[part])) {
|
|
420
|
+
// Convert to array if needed
|
|
421
|
+
const temp = { ...current[part] };
|
|
422
|
+
current[part] = [];
|
|
423
|
+
Object.assign(current[part], temp);
|
|
424
|
+
}
|
|
425
|
+
current = current[part];
|
|
426
|
+
}
|
|
427
|
+
const lastPart = parts[parts.length - 1];
|
|
428
|
+
current[lastPart] = value;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
// Convert objects with sequential numeric keys to arrays
|
|
432
|
+
if (detectArrays) {
|
|
433
|
+
const convertToArrayIfNeeded = (obj) => {
|
|
434
|
+
if (!isObject(obj))
|
|
435
|
+
return obj;
|
|
436
|
+
if (Array.isArray(obj)) {
|
|
437
|
+
return obj.map(convertToArrayIfNeeded);
|
|
438
|
+
}
|
|
439
|
+
// Check if object has sequential numeric keys starting at 0
|
|
440
|
+
const keys = Object.keys(obj);
|
|
441
|
+
const isNumericSequence = keys.length > 0 &&
|
|
442
|
+
keys.every((key, index) => {
|
|
443
|
+
return String(index) === key;
|
|
444
|
+
});
|
|
445
|
+
if (isNumericSequence) {
|
|
446
|
+
return Object.values(obj).map(convertToArrayIfNeeded);
|
|
447
|
+
}
|
|
448
|
+
// Recursively process all values
|
|
449
|
+
const result = {};
|
|
450
|
+
for (const key in obj) {
|
|
451
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
452
|
+
result[key] = convertToArrayIfNeeded(obj[key]);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return result;
|
|
456
|
+
};
|
|
457
|
+
return convertToArrayIfNeeded(result);
|
|
458
|
+
}
|
|
459
|
+
return result;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Transforms object values by applying a series of transform functions
|
|
463
|
+
*
|
|
464
|
+
* Creates a new object with the same structure as the input,
|
|
465
|
+
* but with all values transformed by the provided sequence of functions.
|
|
466
|
+
* Each function is applied in order to the result of the previous function.
|
|
467
|
+
*
|
|
468
|
+
* @template T - The input object type
|
|
469
|
+
* @param obj - The source object
|
|
470
|
+
* @param transformers - One or more transform functions to apply
|
|
471
|
+
* @returns A new object with transformed values
|
|
472
|
+
*
|
|
473
|
+
* @example
|
|
474
|
+
* ```ts
|
|
475
|
+
* const data = {
|
|
476
|
+
* name: ' Alice Smith ',
|
|
477
|
+
* email: 'ALICE@EXAMPLE.COM',
|
|
478
|
+
* score: '85'
|
|
479
|
+
* };
|
|
480
|
+
*
|
|
481
|
+
* // Apply multiple transforms: trim strings, convert to lowercase, and parse numbers
|
|
482
|
+
* const transformed = transformValues(data,
|
|
483
|
+
* value => typeof value === 'string' ? value.trim() : value,
|
|
484
|
+
* value => typeof value === 'string' ? value.toLowerCase() : value,
|
|
485
|
+
* value => !isNaN(Number(value)) ? Number(value) : value
|
|
486
|
+
* );
|
|
487
|
+
*
|
|
488
|
+
* // {
|
|
489
|
+
* // name: 'alice smith',
|
|
490
|
+
* // email: 'alice@example.com',
|
|
491
|
+
* // score: 85
|
|
492
|
+
* // }
|
|
493
|
+
* ```
|
|
494
|
+
*/
|
|
495
|
+
export function transformValues(obj, ...transformers) {
|
|
496
|
+
if (!isObject(obj) || transformers.length === 0) {
|
|
497
|
+
return obj;
|
|
498
|
+
}
|
|
499
|
+
const result = { ...obj };
|
|
500
|
+
for (const key in result) {
|
|
501
|
+
if (Object.prototype.hasOwnProperty.call(result, key)) {
|
|
502
|
+
let value = result[key];
|
|
503
|
+
for (const transformer of transformers) {
|
|
504
|
+
value = transformer(value);
|
|
505
|
+
}
|
|
506
|
+
result[key] = value;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return result;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Renames keys in an object according to a mapping
|
|
513
|
+
*
|
|
514
|
+
* Creates a new object with keys renamed according to the provided mapping.
|
|
515
|
+
* Keys not in the mapping are kept unchanged.
|
|
516
|
+
*
|
|
517
|
+
* @template T - The input object type
|
|
518
|
+
* @param obj - The source object
|
|
519
|
+
* @param mapping - Object mapping from original keys to new keys
|
|
520
|
+
* @param options - Renaming options
|
|
521
|
+
* @param options.removeUnmapped - Whether to remove keys not in the mapping (default: false)
|
|
522
|
+
* @returns A new object with renamed keys
|
|
523
|
+
*
|
|
524
|
+
* @example
|
|
525
|
+
* ```ts
|
|
526
|
+
* const user = {
|
|
527
|
+
* first_name: 'Alice',
|
|
528
|
+
* last_name: 'Smith',
|
|
529
|
+
* email: 'alice@example.com',
|
|
530
|
+
* age: 30
|
|
531
|
+
* };
|
|
532
|
+
*
|
|
533
|
+
* const renamed = renameKeys(user, {
|
|
534
|
+
* first_name: 'firstName',
|
|
535
|
+
* last_name: 'lastName'
|
|
536
|
+
* });
|
|
537
|
+
*
|
|
538
|
+
* // {
|
|
539
|
+
* // firstName: 'Alice',
|
|
540
|
+
* // lastName: 'Smith',
|
|
541
|
+
* // email: 'alice@example.com',
|
|
542
|
+
* // age: 30
|
|
543
|
+
* // }
|
|
544
|
+
* ```
|
|
545
|
+
*/
|
|
546
|
+
export function renameKeys(obj, mapping, options = {}) {
|
|
547
|
+
if (!isObject(obj)) {
|
|
548
|
+
return obj;
|
|
549
|
+
}
|
|
550
|
+
const { removeUnmapped = false } = options;
|
|
551
|
+
const result = {};
|
|
552
|
+
for (const key in obj) {
|
|
553
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
554
|
+
if (key in mapping) {
|
|
555
|
+
result[mapping[key]] = obj[key];
|
|
556
|
+
}
|
|
557
|
+
else if (!removeUnmapped) {
|
|
558
|
+
result[key] = obj[key];
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return result;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Deeply transforms objects, arrays, and values in a nested structure
|
|
566
|
+
*
|
|
567
|
+
* Recursively traverses an object or array and applies different transform functions
|
|
568
|
+
* based on the type of each node (object, array, or primitive value).
|
|
569
|
+
*
|
|
570
|
+
* @template T - The input type
|
|
571
|
+
* @param data - The data to transform
|
|
572
|
+
* @param options - Transform options
|
|
573
|
+
* @param options.transformObject - Function to transform objects (default: identity)
|
|
574
|
+
* @param options.transformArray - Function to transform arrays (default: identity)
|
|
575
|
+
* @param options.transformValue - Function to transform primitive values (default: identity)
|
|
576
|
+
* @param options.maxDepth - Maximum depth to transform (default: Infinity)
|
|
577
|
+
* @returns The transformed data
|
|
578
|
+
*
|
|
579
|
+
* @example
|
|
580
|
+
* ```ts
|
|
581
|
+
* const data = {
|
|
582
|
+
* user: {
|
|
583
|
+
* name: 'Alice Smith',
|
|
584
|
+
* scores: [85, 92, 78],
|
|
585
|
+
* active: true
|
|
586
|
+
* },
|
|
587
|
+
* metadata: {
|
|
588
|
+
* lastUpdated: '2023-01-15'
|
|
589
|
+
* }
|
|
590
|
+
* };
|
|
591
|
+
*
|
|
592
|
+
* // Apply different transformations to objects, arrays, and primitive values
|
|
593
|
+
* const result = deepTransform(data, {
|
|
594
|
+
* transformObject: obj => ({ ...obj, _transformed: true }),
|
|
595
|
+
* transformArray: arr => arr.map(x => typeof x === 'number' ? x + 10 : x),
|
|
596
|
+
* transformValue: (val, key) => key === 'name' ? val.toUpperCase() : val
|
|
597
|
+
* });
|
|
598
|
+
*
|
|
599
|
+
* // {
|
|
600
|
+
* // user: {
|
|
601
|
+
* // name: 'ALICE SMITH',
|
|
602
|
+
* // scores: [95, 102, 88],
|
|
603
|
+
* // active: true,
|
|
604
|
+
* // _transformed: true
|
|
605
|
+
* // },
|
|
606
|
+
* // metadata: {
|
|
607
|
+
* // lastUpdated: '2023-01-15',
|
|
608
|
+
* // _transformed: true
|
|
609
|
+
* // },
|
|
610
|
+
* // _transformed: true
|
|
611
|
+
* // }
|
|
612
|
+
* ```
|
|
613
|
+
*/
|
|
614
|
+
export function deepTransform(data, options = {}) {
|
|
615
|
+
const { transformObject = (x) => x, transformArray = (x) => x, transformValue = (x) => x, maxDepth = Infinity, } = options;
|
|
616
|
+
function transform(value, path = [], depth = 0) {
|
|
617
|
+
if (depth > maxDepth) {
|
|
618
|
+
return value;
|
|
619
|
+
}
|
|
620
|
+
if (Array.isArray(value)) {
|
|
621
|
+
const transformedArray = value.map((item, index) => transform(item, [...path, index.toString()], depth + 1));
|
|
622
|
+
return transformArray(transformedArray, path);
|
|
623
|
+
}
|
|
624
|
+
if (isObject(value)) {
|
|
625
|
+
const transformedObj = {};
|
|
626
|
+
for (const key in value) {
|
|
627
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
628
|
+
const newPath = [...path, key];
|
|
629
|
+
transformedObj[key] = transform(value[key], newPath, depth + 1);
|
|
630
|
+
// Apply value transformation to object properties
|
|
631
|
+
if (!Array.isArray(value[key]) && !isObject(value[key])) {
|
|
632
|
+
transformedObj[key] = transformValue(transformedObj[key], key, newPath);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return transformObject(transformedObj, path);
|
|
637
|
+
}
|
|
638
|
+
// If this is a top-level primitive, it doesn't have a key
|
|
639
|
+
const key = path.length > 0 ? path[path.length - 1] : '';
|
|
640
|
+
return transformValue(value, key, path);
|
|
641
|
+
}
|
|
642
|
+
return transform(data);
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Transforms a flat object with key-value pairs into a structured object by key pattern
|
|
646
|
+
*
|
|
647
|
+
* Useful for converting flat configuration objects or query parameters into structured objects.
|
|
648
|
+
* Groups keys by a shared prefix and nests them accordingly.
|
|
649
|
+
*
|
|
650
|
+
* @param obj - The flat object to structure
|
|
651
|
+
* @param options - Structuring options
|
|
652
|
+
* @param options.separator - The character(s) that separate key parts (default: '.')
|
|
653
|
+
* @param options.detectArrays - Whether to convert numeric indices to arrays (default: true)
|
|
654
|
+
* @returns A structured object
|
|
655
|
+
*
|
|
656
|
+
* @example
|
|
657
|
+
* ```ts
|
|
658
|
+
* const params = {
|
|
659
|
+
* 'user.name': 'Alice',
|
|
660
|
+
* 'user.email': 'alice@example.com',
|
|
661
|
+
* 'preferences.theme': 'dark',
|
|
662
|
+
* 'preferences.notifications': 'true',
|
|
663
|
+
* 'items.0.id': '1001',
|
|
664
|
+
* 'items.0.name': 'Widget',
|
|
665
|
+
* 'items.1.id': '1002',
|
|
666
|
+
* 'items.1.name': 'Gadget'
|
|
667
|
+
* };
|
|
668
|
+
*
|
|
669
|
+
* const structured = structureByKeys(params);
|
|
670
|
+
* // {
|
|
671
|
+
* // user: {
|
|
672
|
+
* // name: 'Alice',
|
|
673
|
+
* // email: 'alice@example.com'
|
|
674
|
+
* // },
|
|
675
|
+
* // preferences: {
|
|
676
|
+
* // theme: 'dark',
|
|
677
|
+
* // notifications: 'true'
|
|
678
|
+
* // },
|
|
679
|
+
* // items: [
|
|
680
|
+
* // { id: '1001', name: 'Widget' },
|
|
681
|
+
* // { id: '1002', name: 'Gadget' }
|
|
682
|
+
* // ]
|
|
683
|
+
* // }
|
|
684
|
+
* ```
|
|
685
|
+
*/
|
|
686
|
+
export function structureByKeys(obj, options = {}) {
|
|
687
|
+
// This is essentially just an alias for unflatten with a more descriptive name
|
|
688
|
+
return unflatten(obj, options);
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Transforms values at specific paths in an object
|
|
692
|
+
*
|
|
693
|
+
* Applies transform functions to values at the specified path(s),
|
|
694
|
+
* supporting advanced path selectors including property paths, array indices,
|
|
695
|
+
* wildcards, and filters. Supports transforming multiple paths in a single operation.
|
|
696
|
+
*
|
|
697
|
+
* @template T - The input object type
|
|
698
|
+
* @param obj - The source object
|
|
699
|
+
* @param paths - Path selector or array of path selectors to the values to transform
|
|
700
|
+
* @param transformer - Function to transform the value
|
|
701
|
+
* @param options - Additional options
|
|
702
|
+
* @param options.transformAll - Whether to apply transformer to all paths or individually (default: false)
|
|
703
|
+
* @returns A new object with the transformed value(s)
|
|
704
|
+
*
|
|
705
|
+
* @example
|
|
706
|
+
* ```ts
|
|
707
|
+
* const user = {
|
|
708
|
+
* id: 1,
|
|
709
|
+
* name: 'Alice Smith',
|
|
710
|
+
* profile: {
|
|
711
|
+
* email: 'alice@example.com',
|
|
712
|
+
* settings: {
|
|
713
|
+
* notifications: true
|
|
714
|
+
* }
|
|
715
|
+
* },
|
|
716
|
+
* posts: [
|
|
717
|
+
* { id: 101, title: 'Hello', likes: 5 },
|
|
718
|
+
* { id: 102, title: 'World', likes: 10 }
|
|
719
|
+
* ]
|
|
720
|
+
* };
|
|
721
|
+
*
|
|
722
|
+
* // Transform a simple property
|
|
723
|
+
* const result1 = transformPath(user, 'name', name => name.toUpperCase());
|
|
724
|
+
* // user.name becomes 'ALICE SMITH'
|
|
725
|
+
*
|
|
726
|
+
* // Transform a nested property
|
|
727
|
+
* const result2 = transformPath(user, 'profile.email', email => email.split('@')[0] + '@example.org');
|
|
728
|
+
* // user.profile.email becomes 'alice@example.org'
|
|
729
|
+
*
|
|
730
|
+
* // Transform using wildcards
|
|
731
|
+
* const result3 = transformPath(user, 'posts[*].likes', likes => likes * 2);
|
|
732
|
+
* // All post likes are doubled
|
|
733
|
+
*
|
|
734
|
+
* // Transform multiple paths
|
|
735
|
+
* const result4 = transformPath(
|
|
736
|
+
* user,
|
|
737
|
+
* ['name', 'profile.email', 'posts[*].likes'],
|
|
738
|
+
* value => {
|
|
739
|
+
* if (typeof value === 'string') return value.toUpperCase();
|
|
740
|
+
* if (typeof value === 'number') return value * 2;
|
|
741
|
+
* return value;
|
|
742
|
+
* }
|
|
743
|
+
* );
|
|
744
|
+
* // Transforms multiple properties at once
|
|
745
|
+
*
|
|
746
|
+
* // Use path-specific transformations
|
|
747
|
+
* const result5 = transformPath(
|
|
748
|
+
* user,
|
|
749
|
+
* ['name', 'profile.email', 'posts[*].likes'],
|
|
750
|
+
* (value, path) => {
|
|
751
|
+
* if (path === 'name') return value.toUpperCase();
|
|
752
|
+
* if (path === 'profile.email') return value.split('@')[0] + '@example.org';
|
|
753
|
+
* if (path.includes('likes')) return value + 10;
|
|
754
|
+
* return value;
|
|
755
|
+
* },
|
|
756
|
+
* { transformAll: true }
|
|
757
|
+
* );
|
|
758
|
+
* ```
|
|
759
|
+
*/
|
|
760
|
+
export function transformPath(obj, paths, transformer, options = {}) {
|
|
761
|
+
if (!isObject(obj)) {
|
|
762
|
+
return obj;
|
|
763
|
+
}
|
|
764
|
+
// Deep clone to avoid modifying the original
|
|
765
|
+
const result = JSON.parse(JSON.stringify(obj));
|
|
766
|
+
const { transformAll = false } = options;
|
|
767
|
+
const pathsArray = Array.isArray(paths) ? paths : [paths];
|
|
768
|
+
// Process each path
|
|
769
|
+
for (const path of pathsArray) {
|
|
770
|
+
if (path.includes('*') || path.includes('[')) {
|
|
771
|
+
// Complex path with wildcards or array access
|
|
772
|
+
const matches = get(result, path, { preserveStructure: true });
|
|
773
|
+
if (matches === undefined) {
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
// Function to collect and transform all matching paths
|
|
777
|
+
function applyTransform(obj, basePath = '') {
|
|
778
|
+
if (!isObject(obj))
|
|
779
|
+
return;
|
|
780
|
+
if (Array.isArray(obj)) {
|
|
781
|
+
obj.forEach((item, index) => {
|
|
782
|
+
const currentPath = basePath
|
|
783
|
+
? `${basePath}[${index}]`
|
|
784
|
+
: `[${index}]`;
|
|
785
|
+
applyTransform(item, currentPath);
|
|
786
|
+
});
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
for (const key in obj) {
|
|
790
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
791
|
+
const value = obj[key];
|
|
792
|
+
const currentPath = basePath ? `${basePath}.${key}` : key;
|
|
793
|
+
// If we've reached a leaf node or primitive value, transform it
|
|
794
|
+
if (value === null || typeof value !== 'object') {
|
|
795
|
+
const parent = basePath ? get(result, basePath) : result;
|
|
796
|
+
const transformed = transformAll
|
|
797
|
+
? transformer(value, currentPath, parent)
|
|
798
|
+
: transformer(value, key, parent);
|
|
799
|
+
obj[key] = transformed;
|
|
800
|
+
}
|
|
801
|
+
else {
|
|
802
|
+
// Continue traversing
|
|
803
|
+
applyTransform(value, currentPath);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
applyTransform(matches);
|
|
809
|
+
// Update the original object with our changes
|
|
810
|
+
const segments = parseSelector(path);
|
|
811
|
+
if (segments.length > 0) {
|
|
812
|
+
const firstSegment = segments[0];
|
|
813
|
+
if (firstSegment.type === 'property') {
|
|
814
|
+
result[String(firstSegment.value)] =
|
|
815
|
+
matches[String(firstSegment.value)];
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
// Simple path - direct property access
|
|
821
|
+
const segments = path.split('.');
|
|
822
|
+
function setValueAtPath(obj, segments, index, fullPath) {
|
|
823
|
+
if (index >= segments.length)
|
|
824
|
+
return obj;
|
|
825
|
+
const key = segments[index];
|
|
826
|
+
if (index === segments.length - 1) {
|
|
827
|
+
// We've reached the target property
|
|
828
|
+
const parent = index > 0
|
|
829
|
+
? setValueAtPath(obj, segments, index - 1, segments.slice(0, index).join('.'))
|
|
830
|
+
: obj;
|
|
831
|
+
const transformed = transformAll
|
|
832
|
+
? transformer(parent[key], fullPath, parent)
|
|
833
|
+
: transformer(parent[key], key, parent);
|
|
834
|
+
parent[key] = transformed;
|
|
835
|
+
return parent;
|
|
836
|
+
}
|
|
837
|
+
// Continue traversing
|
|
838
|
+
const nextObj = obj[key] || {};
|
|
839
|
+
obj[key] = setValueAtPath(nextObj, segments, index + 1, fullPath);
|
|
840
|
+
return obj;
|
|
841
|
+
}
|
|
842
|
+
setValueAtPath(result, segments, 0, path);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return result;
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Maps values at specific paths in an object
|
|
849
|
+
*
|
|
850
|
+
* Similar to transformPath, but returns an array of transformed values
|
|
851
|
+
* rather than modifying the object structure. Supports mapping multiple paths
|
|
852
|
+
* in a single operation.
|
|
853
|
+
*
|
|
854
|
+
* @template T - The input object type
|
|
855
|
+
* @template R - The output value type
|
|
856
|
+
* @param obj - The source object
|
|
857
|
+
* @param paths - Path selector or array of path selectors to the values to map
|
|
858
|
+
* @param mapper - Function to transform each value
|
|
859
|
+
* @param options - Additional options
|
|
860
|
+
* @param options.flatten - Whether to flatten the results into a single array (default: true)
|
|
861
|
+
* @returns An array of transformed values
|
|
862
|
+
*
|
|
863
|
+
* @example
|
|
864
|
+
* ```ts
|
|
865
|
+
* const data = {
|
|
866
|
+
* users: [
|
|
867
|
+
* { id: 1, name: 'Alice', age: 30 },
|
|
868
|
+
* { id: 2, name: 'Bob', age: 25 },
|
|
869
|
+
* { id: 3, name: 'Charlie', age: 35 }
|
|
870
|
+
* ]
|
|
871
|
+
* };
|
|
872
|
+
*
|
|
873
|
+
* // Extract and transform user names
|
|
874
|
+
* const names = mapPath(data, 'users[*].name', name => name.toUpperCase());
|
|
875
|
+
* // ['ALICE', 'BOB', 'CHARLIE']
|
|
876
|
+
*
|
|
877
|
+
* // Filter and transform
|
|
878
|
+
* const youngUsers = mapPath(data, 'users[?(@.age < 30)].name', (name, user) => ({
|
|
879
|
+
* name,
|
|
880
|
+
* greeting: `Hello, ${name}!`
|
|
881
|
+
* }));
|
|
882
|
+
* // [{ name: 'Bob', greeting: 'Hello, Bob!' }]
|
|
883
|
+
*
|
|
884
|
+
* // Map multiple paths
|
|
885
|
+
* const info = mapPath(
|
|
886
|
+
* data,
|
|
887
|
+
* ['users[*].name', 'users[*].age'],
|
|
888
|
+
* value => typeof value === 'string' ? value.toUpperCase() : value
|
|
889
|
+
* );
|
|
890
|
+
* // ['ALICE', 'BOB', 'CHARLIE', 30, 25, 35]
|
|
891
|
+
*
|
|
892
|
+
* // Map multiple paths with path context
|
|
893
|
+
* const info = mapPath(
|
|
894
|
+
* data,
|
|
895
|
+
* ['users[*].name', 'users[*].age'],
|
|
896
|
+
* (value, path) => {
|
|
897
|
+
* if (path.includes('name')) return `Name: ${value}`;
|
|
898
|
+
* if (path.includes('age')) return `Age: ${value}`;
|
|
899
|
+
* return value;
|
|
900
|
+
* }
|
|
901
|
+
* );
|
|
902
|
+
* // ['Name: Alice', 'Name: Bob', 'Name: Charlie', 'Age: 30', 'Age: 25', 'Age: 35']
|
|
903
|
+
* ```
|
|
904
|
+
*/
|
|
905
|
+
export function mapPath(obj, paths, mapper, options = {}) {
|
|
906
|
+
if (!isObject(obj)) {
|
|
907
|
+
return [];
|
|
908
|
+
}
|
|
909
|
+
const { flatten = true } = options;
|
|
910
|
+
const pathsArray = Array.isArray(paths) ? paths : [paths];
|
|
911
|
+
// Process each path
|
|
912
|
+
const results = pathsArray.map((path) => {
|
|
913
|
+
const values = get(obj, path);
|
|
914
|
+
if (values === undefined) {
|
|
915
|
+
return [];
|
|
916
|
+
}
|
|
917
|
+
if (Array.isArray(values)) {
|
|
918
|
+
return values.map((value, index) => {
|
|
919
|
+
const fullPath = `${path}[${index}]`;
|
|
920
|
+
return mapper(value, fullPath, obj);
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
return [mapper(values, path, obj)];
|
|
924
|
+
});
|
|
925
|
+
// Return flattened or grouped results
|
|
926
|
+
return flatten ? results.flat() : results;
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Transforms keys at specific paths in an object
|
|
930
|
+
*
|
|
931
|
+
* Applies a transform function to keys at the specified path(s),
|
|
932
|
+
* supporting advanced path selectors. Supports transforming keys at multiple paths
|
|
933
|
+
* in a single operation.
|
|
934
|
+
*
|
|
935
|
+
* @template T - The input object type
|
|
936
|
+
* @param obj - The source object
|
|
937
|
+
* @param paths - Path selector or array of path selectors to the objects whose keys should be transformed
|
|
938
|
+
* @param transformer - Function to transform each key
|
|
939
|
+
* @param options - Additional options
|
|
940
|
+
* @param options.recursive - Whether to recursively transform nested object keys (default: false)
|
|
941
|
+
* @returns A new object with transformed keys at the specified path(s)
|
|
942
|
+
*
|
|
943
|
+
* @example
|
|
944
|
+
* ```ts
|
|
945
|
+
* const data = {
|
|
946
|
+
* user: {
|
|
947
|
+
* personal_info: {
|
|
948
|
+
* first_name: 'Alice',
|
|
949
|
+
* last_name: 'Smith',
|
|
950
|
+
* email_address: 'alice@example.com'
|
|
951
|
+
* },
|
|
952
|
+
* work_info: {
|
|
953
|
+
* job_title: 'Developer',
|
|
954
|
+
* department_name: 'Engineering'
|
|
955
|
+
* }
|
|
956
|
+
* }
|
|
957
|
+
* };
|
|
958
|
+
*
|
|
959
|
+
* // Transform snake_case keys to camelCase at a single path
|
|
960
|
+
* const result1 = transformKeysAtPath(data, 'user.personal_info', key =>
|
|
961
|
+
* key.replace(/_([a-z])/g, (_, c) => c.toUpperCase())
|
|
962
|
+
* );
|
|
963
|
+
*
|
|
964
|
+
* // Transform keys at multiple paths
|
|
965
|
+
* const result2 = transformKeysAtPath(
|
|
966
|
+
* data,
|
|
967
|
+
* ['user.personal_info', 'user.work_info'],
|
|
968
|
+
* key => key.replace(/_([a-z])/g, (_, c) => c.toUpperCase())
|
|
969
|
+
* );
|
|
970
|
+
*
|
|
971
|
+
* // Recursively transform all nested keys
|
|
972
|
+
* const result3 = transformKeysAtPath(
|
|
973
|
+
* data,
|
|
974
|
+
* 'user',
|
|
975
|
+
* key => key.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),
|
|
976
|
+
* { recursive: true }
|
|
977
|
+
* );
|
|
978
|
+
*
|
|
979
|
+
* // Result3:
|
|
980
|
+
* // {
|
|
981
|
+
* // user: {
|
|
982
|
+
* // personalInfo: {
|
|
983
|
+
* // firstName: 'Alice',
|
|
984
|
+
* // lastName: 'Smith',
|
|
985
|
+
* // emailAddress: 'alice@example.com'
|
|
986
|
+
* // },
|
|
987
|
+
* // workInfo: {
|
|
988
|
+
* // jobTitle: 'Developer',
|
|
989
|
+
* // departmentName: 'Engineering'
|
|
990
|
+
* // }
|
|
991
|
+
* // }
|
|
992
|
+
* // }
|
|
993
|
+
* ```
|
|
994
|
+
*/
|
|
995
|
+
export function transformKeysAtPath(obj, paths, transformer, options = {}) {
|
|
996
|
+
if (!isObject(obj)) {
|
|
997
|
+
return obj;
|
|
998
|
+
}
|
|
999
|
+
// Deep clone to avoid modifying the original
|
|
1000
|
+
const result = JSON.parse(JSON.stringify(obj));
|
|
1001
|
+
const { recursive = false } = options;
|
|
1002
|
+
const pathsArray = Array.isArray(paths) ? paths : [paths];
|
|
1003
|
+
for (const path of pathsArray) {
|
|
1004
|
+
// Get the object at the specified path
|
|
1005
|
+
const target = path ? get(result, path) : result;
|
|
1006
|
+
if (!isObject(target)) {
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
// Function to recursively transform object keys
|
|
1010
|
+
const transformObjectKeys = (obj, currentPath = path) => {
|
|
1011
|
+
if (!isObject(obj)) {
|
|
1012
|
+
return obj;
|
|
1013
|
+
}
|
|
1014
|
+
if (Array.isArray(obj)) {
|
|
1015
|
+
return obj.map((item, index) => isObject(item) && !Array.isArray(item)
|
|
1016
|
+
? transformObjectKeys(item, `${currentPath}[${index}]`)
|
|
1017
|
+
: item);
|
|
1018
|
+
}
|
|
1019
|
+
const transformed = {};
|
|
1020
|
+
for (const key in obj) {
|
|
1021
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
1022
|
+
const newKey = transformer(key, obj[key], currentPath);
|
|
1023
|
+
// Recursively transform nested objects if option is enabled
|
|
1024
|
+
if (recursive && isObject(obj[key])) {
|
|
1025
|
+
transformed[newKey] = transformObjectKeys(obj[key], `${currentPath}.${newKey}`);
|
|
1026
|
+
}
|
|
1027
|
+
else {
|
|
1028
|
+
transformed[newKey] = obj[key];
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
return transformed;
|
|
1033
|
+
};
|
|
1034
|
+
if (Array.isArray(target)) {
|
|
1035
|
+
// Handle arrays of objects
|
|
1036
|
+
for (let i = 0; i < target.length; i++) {
|
|
1037
|
+
if (isObject(target[i]) && !Array.isArray(target[i])) {
|
|
1038
|
+
target[i] = transformObjectKeys(target[i], `${path}[${i}]`);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
else {
|
|
1043
|
+
// Handle plain objects
|
|
1044
|
+
const transformed = transformObjectKeys(target);
|
|
1045
|
+
// Update the object at path
|
|
1046
|
+
if (path) {
|
|
1047
|
+
set(result, path, transformed);
|
|
1048
|
+
}
|
|
1049
|
+
else {
|
|
1050
|
+
Object.keys(result).forEach((key) => {
|
|
1051
|
+
delete result[key];
|
|
1052
|
+
});
|
|
1053
|
+
Object.assign(result, transformed);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
return result;
|
|
1058
|
+
}
|