| 195 | } |
| 196 | |
| 197 | function _dropUndefinedKeys<T>(inputValue: T, memoizationMap: Map<unknown, unknown>): T { |
| 198 | // Early return for primitive values |
| 199 | if (inputValue === null || typeof inputValue !== 'object') { |
| 200 | return inputValue; |
| 201 | } |
| 202 | |
| 203 | // Check memo map first for all object types |
| 204 | const memoVal = memoizationMap.get(inputValue); |
| 205 | if (memoVal !== undefined) { |
| 206 | return memoVal as T; |
| 207 | } |
| 208 | |
| 209 | // handle arrays |
| 210 | if (Array.isArray(inputValue)) { |
| 211 | const returnValue: unknown[] = []; |
| 212 | // Store mapping to handle circular references |
| 213 | memoizationMap.set(inputValue, returnValue); |
| 214 | |
| 215 | inputValue.forEach(value => { |
| 216 | returnValue.push(_dropUndefinedKeys(value, memoizationMap)); |
| 217 | }); |
| 218 | |
| 219 | return returnValue as unknown as T; |
| 220 | } |
| 221 | |
| 222 | if (isPojo(inputValue)) { |
| 223 | const returnValue: { [key: string]: unknown } = {}; |
| 224 | // Store mapping to handle circular references |
| 225 | memoizationMap.set(inputValue, returnValue); |
| 226 | |
| 227 | const keys = Object.keys(inputValue); |
| 228 | |
| 229 | keys.forEach(key => { |
| 230 | const val = inputValue[key]; |
| 231 | if (val !== undefined) { |
| 232 | returnValue[key] = _dropUndefinedKeys(val, memoizationMap); |
| 233 | } |
| 234 | }); |
| 235 | |
| 236 | return returnValue as T; |
| 237 | } |
| 238 | |
| 239 | // For other object types, return as is |
| 240 | return inputValue; |
| 241 | } |
| 242 | |
| 243 | function isPojo(input: unknown): input is Record<string, unknown> { |
| 244 | // Plain objects have Object as constructor or no constructor |