( obj: any, filter: (key: string, value: T) => boolean, visited = new WeakSet(), deep = 0 )
| 4 | // If the callback returns true, |
| 5 | // keep the key; otherwise, delete it. |
| 6 | export function deepTraverseObject<T = any>( |
| 7 | obj: any, |
| 8 | filter: (key: string, value: T) => boolean, |
| 9 | visited = new WeakSet(), |
| 10 | deep = 0 |
| 11 | ) { |
| 12 | if (deep > 5) { |
| 13 | return obj; |
| 14 | } |
| 15 | // Prevent infinite recursion: check if object was already visited (handles circular references) |
| 16 | if (obj && typeof obj === "object") { |
| 17 | if (visited.has(obj)) { |
| 18 | return obj; |
| 19 | } |
| 20 | visited.add(obj); |
| 21 | } |
| 22 | |
| 23 | for (const key in obj) { |
| 24 | if (!filter(key, obj[key])) { |
| 25 | obj[key] = undefined; |
| 26 | delete obj[key]; |
| 27 | continue; |
| 28 | } |
| 29 | // Only recurse into objects and arrays |
| 30 | if (obj[key] && typeof obj[key] === "object") { |
| 31 | deepTraverseObject(obj[key], filter, visited, deep + 1); |
| 32 | } |
| 33 | } |
| 34 | return obj; |
| 35 | } |
| 36 | |
| 37 | export function filterEmptyFields<T = any>(obj: T) { |
| 38 | return deepTraverseObject(obj, (_, value) => { |
no test coverage detected