Skip to content

Commit ef336c3

Browse files
lforstAbhiPrasad
authored andcommitted
ref(utils): Add logic to enable skipping of normalization (#5052)
1 parent 7179200 commit ef336c3

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

packages/utils/src/normalize.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type ObjOrArray<T> = { [key: string]: T };
3333
*/
3434
export function normalize(input: unknown, depth: number = +Infinity, maxProperties: number = +Infinity): any {
3535
try {
36-
// since we're at the outermost level, there is no key
36+
// since we're at the outermost level, we don't provide a key
3737
return visit('', input, depth, maxProperties);
3838
} catch (err) {
3939
return { ERROR: `**non-serializable** (${err})` };
@@ -98,6 +98,15 @@ function visit(
9898
return stringified;
9999
}
100100

101+
// From here on, we can assert that `value` is either an object or an array.
102+
103+
// Do not normalize objects that we know have already been normalized. As a general rule, the
104+
// "__sentry_skip_normalization__" property should only be used sparingly and only should only be set on objects that
105+
// have already been normalized.
106+
if ((value as ObjOrArray<unknown>)['__sentry_skip_normalization__']) {
107+
return value as ObjOrArray<unknown>;
108+
}
109+
101110
// We're also done if we've reached the max depth
102111
if (depth === 0) {
103112
// At this point we know `serialized` is a string of the form `"[object XXXX]"`. Clean it up so it's just `"[XXXX]"`.

packages/utils/test/normalize.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import * as isModule from '../src/is';
66
import { normalize } from '../src/normalize';
7+
import { addNonEnumerableProperty } from '../src/object';
78
import * as stacktraceModule from '../src/stacktrace';
89

910
describe('normalize()', () => {
@@ -504,4 +505,52 @@ describe('normalize()', () => {
504505
qux: '[Function: qux]',
505506
});
506507
});
508+
509+
describe('skips normalizing objects marked with a non-enumerable property __sentry_skip_normalization__', () => {
510+
test('by leaving non-serializable values intact', () => {
511+
const someFun = () => undefined;
512+
const alreadyNormalizedObj = {
513+
nan: NaN,
514+
fun: someFun,
515+
};
516+
517+
addNonEnumerableProperty(alreadyNormalizedObj, '__sentry_skip_normalization__', true);
518+
519+
const result = normalize(alreadyNormalizedObj);
520+
expect(result).toEqual({
521+
nan: NaN,
522+
fun: someFun,
523+
});
524+
});
525+
526+
test('by ignoring normalization depth', () => {
527+
const alreadyNormalizedObj = {
528+
three: {
529+
more: {
530+
layers: '!',
531+
},
532+
},
533+
};
534+
535+
addNonEnumerableProperty(alreadyNormalizedObj, '__sentry_skip_normalization__', true);
536+
537+
const obj = {
538+
foo: {
539+
bar: {
540+
baz: alreadyNormalizedObj,
541+
boo: {
542+
bam: {
543+
pow: 'poof',
544+
},
545+
},
546+
},
547+
},
548+
};
549+
550+
const result = normalize(obj, 4);
551+
552+
expect(result?.foo?.bar?.baz?.three?.more?.layers).toBe('!');
553+
expect(result?.foo?.bar?.boo?.bam?.pow).not.toBe('poof');
554+
});
555+
});
507556
});

0 commit comments

Comments
 (0)