diff --git a/src/lib/util/flattenPayload.test.ts b/src/lib/util/flattenPayload.test.ts new file mode 100644 index 0000000000..6531a754ff --- /dev/null +++ b/src/lib/util/flattenPayload.test.ts @@ -0,0 +1,35 @@ +import { flattenPayload } from './flattenPayload'; + +describe('flattenPayload', () => { + it('should flatten a payload', () => { + const payload = { + a: 1, + b: { + c: 2, + d: [3, 4], + e: { + f: 5, + }, + }, + }; + expect(flattenPayload(payload)).toEqual({ + a: 1, + 'b.c': 2, + 'b.d[0]': 3, + 'b.d[1]': 4, + 'b.e.f': 5, + }); + }); + + it('should handle conflicting keys gracefully by prioritizing later keys', () => { + const payload = { + a: { + b: 1, + }, + 'a.b': 2, + }; + expect(flattenPayload(payload)).toEqual({ + 'a.b': 2, + }); + }); +}); diff --git a/src/lib/util/flattenPayload.ts b/src/lib/util/flattenPayload.ts new file mode 100644 index 0000000000..78cc6034ff --- /dev/null +++ b/src/lib/util/flattenPayload.ts @@ -0,0 +1,32 @@ +export const flattenPayload = ( + payload = {}, + parentKey = '', +): Record => + Object.entries(payload).reduce((acc, [key, value]) => { + const newKey = parentKey ? `${parentKey}.${key}` : key; + + if ( + typeof value === 'object' && + value !== null && + !Array.isArray(value) + ) { + // If it's an object, recurse and merge the results + Object.assign(acc, flattenPayload(value, newKey)); + } else if (Array.isArray(value)) { + // If it's an array, map through it and handle objects and non-objects differently + value.forEach((item, index) => { + if (typeof item === 'object' && item !== null) { + Object.assign( + acc, + flattenPayload(item, `${newKey}[${index}]`), + ); + } else { + acc[`${newKey}[${index}]`] = item; + } + }); + } else { + acc[newKey] = value; + } + + return acc; + }, {});