11import { SentryWrappedFunction } from '@sentry/types' ;
2- import { isArray , isNaN , isPlainObject , isPrimitive , isSyntheticEvent , isUndefined } from './is' ;
2+ import { isArray , isError , isNaN , isPlainObject , isPrimitive , isSyntheticEvent , isUndefined } from './is' ;
33import { Memo } from './memo' ;
44import { truncate } from './string' ;
55
@@ -120,19 +120,19 @@ function jsonSize(value: any): number {
120120}
121121
122122/** JSDoc */
123- function serializeValue < T > ( value : T ) : T | string {
123+ function serializeValue ( value : any ) : string {
124124 const type = Object . prototype . toString . call ( value ) ;
125125
126+ // Node.js REPL notation
126127 if ( typeof value === 'string' ) {
127128 return truncate ( value , 40 ) ;
128129 } else if ( type === '[object Object]' ) {
129- // Node.js REPL notation
130130 return '[Object]' ;
131131 } else if ( type === '[object Array]' ) {
132- // Node.js REPL notation
133132 return '[Array]' ;
134133 } else {
135- return normalizeValue ( value ) as T ;
134+ const normalized = normalizeValue ( value ) ;
135+ return isPrimitive ( normalized ) ? `${ normalized } ` : ( type as string ) ;
136136 }
137137}
138138
@@ -270,31 +270,27 @@ function objectifyError(error: ExtendedError): object {
270270 * - serializes Error objects
271271 * - filter global objects
272272 */
273- function normalizeValue ( value : any , key ?: any ) : any {
274- if ( key === 'domain' && typeof value === 'object' && ( value as { _events : any } ) . _events ) {
273+ function normalizeValue < T > ( value : T , key ?: any ) : T | string {
274+ if ( key === 'domain' && typeof value === 'object' && ( ( value as unknown ) as { _events : any } ) . _events ) {
275275 return '[Domain]' ;
276276 }
277277
278278 if ( key === 'domainEmitter' ) {
279279 return '[DomainEmitter]' ;
280280 }
281281
282- if ( typeof ( global as any ) !== 'undefined' && value === global ) {
282+ if ( typeof ( global as any ) !== 'undefined' && ( value as unknown ) === global ) {
283283 return '[Global]' ;
284284 }
285285
286- if ( typeof ( window as any ) !== 'undefined' && value === window ) {
286+ if ( typeof ( window as any ) !== 'undefined' && ( value as unknown ) === window ) {
287287 return '[Window]' ;
288288 }
289289
290- if ( typeof ( document as any ) !== 'undefined' && value === document ) {
290+ if ( typeof ( document as any ) !== 'undefined' && ( value as unknown ) === document ) {
291291 return '[Document]' ;
292292 }
293293
294- if ( value instanceof Error ) {
295- return objectifyError ( value ) ;
296- }
297-
298294 // tslint:disable-next-line:strict-type-predicates
299295 if ( typeof Event !== 'undefined' && value instanceof Event ) {
300296 return Object . getPrototypeOf ( value ) ? value . constructor . name : 'Event' ;
@@ -314,7 +310,7 @@ function normalizeValue(value: any, key?: any): any {
314310 }
315311
316312 if ( typeof value === 'function' ) {
317- return `[Function: ${ ( value as ( ) => void ) . name || '<unknown-function-name>' } ]` ;
313+ return `[Function: ${ value . name || '<unknown-function-name>' } ]` ;
318314 }
319315
320316 return value ;
@@ -326,31 +322,34 @@ function normalizeValue(value: any, key?: any): any {
326322 * @param obj Object to be decycled
327323 * @param memo Optional Memo class handling decycling
328324 */
329- export function decycle ( obj : any , memo : Memo = new Memo ( ) ) : any {
330- // tslint:disable-next-line:no-unsafe-any
331- const copy = isArray ( obj ) ? obj . slice ( ) : isPlainObject ( obj ) ? assign ( { } , obj ) : obj ;
332- const normalized = normalizeValue ( obj ) ;
325+ export function decycle ( obj : any , depth : number = + Infinity , memo : Memo = new Memo ( ) ) : any {
326+ if ( depth === 0 ) {
327+ return serializeValue ( obj ) ;
328+ }
333329
334330 // If an object was normalized to its string form, we should just bail out as theres no point in going down that branch
335- if ( typeof normalized === 'string' ) {
331+ const normalized = normalizeValue ( obj ) ;
332+ if ( isPrimitive ( normalized ) ) {
336333 return normalized ;
337334 }
338335
339- if ( ! isPrimitive ( obj ) ) {
340- if ( memo . memoize ( obj ) ) {
341- return '[Circular ~]' ;
342- }
343- // tslint:disable-next-line
344- for ( const key in obj ) {
345- // Avoid iterating over fields in the prototype if they've somehow been exposed to enumeration.
346- if ( ! Object . prototype . hasOwnProperty . call ( obj , key ) ) {
347- continue ;
348- }
349- // tslint:disable-next-line
350- copy [ key ] = decycle ( obj [ key ] , memo ) ;
336+ // tslint:disable-next-line:no-unsafe-any
337+ const source = ( isError ( obj ) ? objectifyError ( obj ) : obj ) as {
338+ [ key : string ] : any ;
339+ } ;
340+ const copy = isArray ( obj ) ? [ ] : { } ;
341+
342+ if ( memo . memoize ( obj ) ) {
343+ return '[Circular ~]' ;
344+ }
345+ for ( const key in source ) {
346+ // Avoid iterating over fields in the prototype if they've somehow been exposed to enumeration.
347+ if ( ! Object . prototype . hasOwnProperty . call ( source , key ) ) {
348+ continue ;
351349 }
352- memo . unmemoize ( obj ) ;
350+ ( copy as { [ key : string ] : any } ) [ key ] = decycle ( source [ key ] , depth - 1 , memo ) ;
353351 }
352+ memo . unmemoize ( obj ) ;
354353
355354 return copy ;
356355}
@@ -362,19 +361,22 @@ export function decycle(obj: any, memo: Memo = new Memo()): any {
362361 * translates undefined/NaN values to "[undefined]"/"[NaN]" respectively,
363362 * and takes care of Error objects serialization
364363 */
365- function serializer ( options : { normalize : boolean } = { normalize : true } ) : ( key : string , value : any ) => any {
366- // tslint:disable-next-line
367- return ( key : string , value : object ) => ( options . normalize ? normalizeValue ( decycle ( value ) , key ) : decycle ( value ) ) ;
364+ function serializer (
365+ options : { normalize ?: boolean ; depth ?: number } = { normalize : true } ,
366+ ) : ( key : string , value : any ) => any {
367+ return ( key : string , value : object ) =>
368+ // tslint:disable-next-line
369+ options . normalize ? normalizeValue ( decycle ( value , options . depth ) , key ) : decycle ( value , options . depth ) ;
368370}
369371
370372/**
371373 * safeNormalize()
372374 *
373375 * Creates a copy of the input by applying serializer function on it and parsing it back to unify the data
374376 */
375- export function safeNormalize ( input : any ) : any {
377+ export function safeNormalize ( input : any , depth ?: number ) : any {
376378 try {
377- return JSON . parse ( JSON . stringify ( input , serializer ( { normalize : true } ) ) ) ;
379+ return JSON . parse ( JSON . stringify ( input , serializer ( { normalize : true , depth } ) ) ) ;
378380 } catch ( _oO ) {
379381 return '**non-serializable**' ;
380382 }
0 commit comments