Skip to content

Commit

Permalink
fix(utils): Fix infinite recursion in dropUndefinedKeys (#5163)
Browse files Browse the repository at this point in the history
  • Loading branch information
lforst authored and AbhiPrasad committed May 30, 2022
1 parent bc73dc0 commit 918d470
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 2 deletions.
22 changes: 20 additions & 2 deletions packages/utils/src/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { WrappedFunction } from '@sentry/types';

import { htmlTreeAsString } from './browser';
import { isElement, isError, isEvent, isInstanceOf, isPlainObject, isPrimitive } from './is';
import { memoBuilder, MemoFunc } from './memo';
import { truncate } from './string';

/**
Expand Down Expand Up @@ -205,20 +206,37 @@ export function extractExceptionKeysForMessage(exception: Record<string, unknown
/**
* Given any object, return the new object with removed keys that value was `undefined`.
* Works recursively on objects and arrays.
*
* Attention: This function keeps circular references in the returned object.
*/
export function dropUndefinedKeys<T>(val: T): T {
// This function just proxies `_dropUndefinedKeys` to keep the `memoBuilder` out of this function's API
return _dropUndefinedKeys(val, memoBuilder());
}

function _dropUndefinedKeys<T>(val: T, memo: MemoFunc): T {
const [memoize] = memo; // we don't need unmemoize because we don't need to visit nodes twice

if (isPlainObject(val)) {
if (memoize(val)) {
return val;
}
const rv: { [key: string]: any } = {};
for (const key of Object.keys(val)) {
if (typeof val[key] !== 'undefined') {
rv[key] = dropUndefinedKeys(val[key]);
rv[key] = _dropUndefinedKeys(val[key], memo);
}
}
return rv as T;
}

if (Array.isArray(val)) {
return (val as any[]).map(dropUndefinedKeys) as any;
if (memoize(val)) {
return val;
}
return (val as any[]).map(item => {
return _dropUndefinedKeys(item, memo);
}) as any;
}

return val;
Expand Down
41 changes: 41 additions & 0 deletions packages/utils/test/object.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,47 @@ describe('dropUndefinedKeys()', () => {
},
});
});

test('objects with circular reference', () => {
const dog: any = {
food: undefined,
};

const human = {
brain: undefined,
pets: dog,
};

const rat = {
scares: human,
weight: '4kg',
};

dog.chases = rat;

expect(dropUndefinedKeys(human)).toStrictEqual({
pets: {
chases: rat,
},
});
});

test('arrays with circular reference', () => {
const egg: any[] = [];

const chicken = {
food: undefined,
weight: '1kg',
lays: egg,
};

egg[0] = chicken;

expect(dropUndefinedKeys(chicken)).toStrictEqual({
lays: egg,
weight: '1kg',
});
});
});

describe('objectify()', () => {
Expand Down

0 comments on commit 918d470

Please sign in to comment.