Skip to content

Commit d3a5689

Browse files
fix: parse nested objects (#119)
1 parent ea620d2 commit d3a5689

File tree

2 files changed

+58
-17
lines changed

2 files changed

+58
-17
lines changed

src/api/common/utils.spec.tsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,49 @@ describe('utils', () => {
5858
});
5959
});
6060

61+
describe('toCamelCase with nested objects', () => {
62+
it('should convert to camelCase only snake_case keys', () => {
63+
const obj = {
64+
user: {
65+
foo_bar: 'foo',
66+
bar_baz: 'bar',
67+
nested_object: {
68+
another_key: 'value',
69+
yet_another_key: 'another value',
70+
},
71+
},
72+
};
73+
const expected = {
74+
user: {
75+
fooBar: 'foo',
76+
barBaz: 'bar',
77+
nestedObject: {
78+
anotherKey: 'value',
79+
yetAnotherKey: 'another value',
80+
},
81+
},
82+
};
83+
expect(toCamelCase(obj)).toEqual(expected);
84+
});
85+
});
86+
87+
describe('toSnakeCase with nested objects', () => {
88+
89+
it('should convert to snake_case only camelCase keys', () => {
90+
const obj = { user: {
91+
fooBar: 'foo',
92+
barBaz: 'bar',
93+
foo_bar: 'foo',
94+
bar_baz: 'bar',
95+
}};
96+
const expected = { user: {
97+
foo_bar: 'foo',
98+
bar_baz: 'bar',
99+
}}
100+
expect(toSnakeCase(obj)).toEqual(expected);
101+
});
102+
});
103+
61104
describe('getUrlParameters', () => {
62105
it('should return null for a null URL', () => {
63106
const result = getUrlParameters(null);

src/api/common/utils.tsx

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,36 +48,34 @@ export const getNextPageParam: GetPreviousPageParamFunction<
4848

4949
type GenericObject = { [key: string]: unknown };
5050

51+
function isGenericObject(value: unknown): value is GenericObject {
52+
return typeof value === "object" && value !== null && !Array.isArray(value);
53+
}
54+
5155
export const toCamelCase = (obj: GenericObject): GenericObject => {
5256
const newObj: GenericObject = {};
5357
for (const key in obj) {
5458
if (Object.hasOwn(obj, key)) {
55-
if (key.includes('_')) {
56-
const newKey = key.replace(/_([a-z])/g, (g) => g[1].toUpperCase());
57-
newObj[newKey] = obj[key];
59+
const newKey = key.replace(/_([a-z])/g, (g) => g[1].toUpperCase());
60+
const value = obj[key]
61+
if (isGenericObject(value)) {
62+
newObj[newKey] = toCamelCase(value);
5863
} else {
59-
newObj[key] = obj[key];
64+
newObj[newKey] = value;
6065
}
6166
}
6267
}
6368
return newObj;
6469
};
6570

71+
const camelToSnake = (key: string): string => key.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
72+
6673
export const toSnakeCase = (obj: GenericObject): GenericObject => {
6774
const newObj: GenericObject = {};
68-
for (const key in obj) {
69-
if (Object.hasOwn(obj, key)) {
70-
let newKey = key.match(/([A-Z])/g)
71-
? key
72-
.match(/([A-Z])/g)!
73-
.reduce(
74-
(str, c) => str.replace(new RegExp(c), `_${c.toLowerCase()}`),
75-
key,
76-
)
77-
: key;
78-
newKey = newKey.substring(key.slice(0, 1).match(/([A-Z])/g) ? 1 : 0);
79-
newObj[newKey] = obj[key];
80-
}
75+
76+
for (const [key, value] of Object.entries(obj)) {
77+
const newKey = camelToSnake(key);
78+
newObj[newKey] = isGenericObject(value) && value !== null ? toSnakeCase(value) : value;
8179
}
8280
return newObj;
8381
};

0 commit comments

Comments
 (0)