11import { SentryWrappedFunction } from '@sentry/types' ;
22import { isNaN , isPlainObject , isUndefined } from './is' ;
3+ import { truncate } from './string' ;
34
45/**
56 * Just an Error object with arbitrary attributes attached to it.
@@ -11,17 +12,12 @@ interface ExtendedError extends Error {
1112/**
1213 * Serializes the given object into a string.
1314 * Like JSON.stringify, but doesn't throw on circular references.
14- * Based on a `json-stringify-safe` package and modified to handle Errors serialization.
15- *
16- * The object must be serializable, i.e.:
17- * - Only primitive types are allowed (object, array, number, string, boolean)
18- * - Its depth should be considerably low for performance reasons
1915 *
2016 * @param object A JSON-serializable object.
2117 * @returns A string containing the serialized object.
2218 */
2319export function serialize < T > ( object : T ) : string {
24- return JSON . stringify ( object ) ;
20+ return JSON . stringify ( object , serializer ( { normalize : false } ) ) ;
2521}
2622
2723/**
@@ -105,34 +101,19 @@ function jsonSize(value: any): number {
105101
106102/** JSDoc */
107103function serializeValue < T > ( value : T ) : T | string {
108- const maxLength = 40 ;
109-
110- if ( typeof value === 'string' ) {
111- return value . length <= maxLength ? value : `${ value . substr ( 0 , maxLength - 1 ) } \u2026` ;
112- } else if ( typeof value === 'number' || typeof value === 'boolean' || typeof value === 'undefined' ) {
113- return value ;
114- } else if ( isNaN ( value ) ) {
115- // NaN and undefined are not JSON.parseable, but we want to preserve this information
116- return '[NaN]' ;
117- } else if ( isUndefined ( value ) ) {
118- return '[undefined]' ;
119- }
120-
121104 const type = Object . prototype . toString . call ( value ) ;
122105
123- // Node.js REPL notation
124- if ( type === '[object Object]' ) {
106+ if ( typeof value === 'string' ) {
107+ return truncate ( value , 40 ) ;
108+ } else if ( type === '[object Object]' ) {
109+ // Node.js REPL notation
125110 return '[Object]' ;
126- }
127- if ( type === '[object Array]' ) {
111+ } else if ( type === '[object Array]' ) {
112+ // Node.js REPL notation
128113 return '[Array]' ;
114+ } else {
115+ return normalizeValue ( value ) as T ;
129116 }
130- if ( type === '[object Function]' ) {
131- const name = ( ( value as any ) as ( ( ) => void ) ) . name ;
132- return name ? `[Function: ${ name } ]` : '[Function]' ;
133- }
134-
135- return value ;
136117}
137118
138119/** JSDoc */
@@ -261,13 +242,15 @@ function objectifyError(error: ExtendedError): object {
261242}
262243
263244/**
264- * standardizeValue ()
245+ * normalizeValue ()
265246 *
266- * translates undefined/NaN values to "[undefined]"/"[NaN]" respectively,
267- * serializes Error objects
268- * filter global objects
247+ * Takes unserializable input and make it serializable friendly
248+ *
249+ * - translates undefined/NaN values to "[undefined]"/"[NaN]" respectively,
250+ * - serializes Error objects
251+ * - filter global objects
269252 */
270- function standardizeValue ( value : any , key : any ) : any {
253+ function normalizeValue ( value : any , key ? : any ) : any {
271254 if ( key === 'domain' && typeof value === 'object' && ( value as { _events : any } ) . _events ) {
272255 return '[Domain]' ;
273256 }
@@ -305,25 +288,25 @@ function standardizeValue(value: any, key: any): any {
305288 }
306289
307290 if ( typeof value === 'function' ) {
308- return `[Function] ${ ( value as ( ) => void ) . name || '<unknown-function-name>' } ` ;
291+ return `[Function: ${ ( value as ( ) => void ) . name || '<unknown-function-name>' } ] ` ;
309292 }
310293
311294 return value ;
312295}
313296
314297/**
315- * standardizer ()
298+ * serializer ()
316299 *
317300 * Remove circular references,
318301 * translates undefined/NaN values to "[undefined]"/"[NaN]" respectively,
319302 * and takes care of Error objects serialization
320303 */
321- function standardizer ( ) : ( key : string , value : any ) => any {
304+ function serializer ( options : { normalize : boolean } = { normalize : true } ) : ( key : string , value : any ) => any {
322305 const stack : any [ ] = [ ] ;
323306 const keys : string [ ] = [ ] ;
324307
325308 /** recursive */
326- function cycleStandardizer ( _key : string , value : any ) : any {
309+ function cycleserializer ( _key : string , value : any ) : any {
327310 if ( stack [ 0 ] === value ) {
328311 return '[Circular ~]' ;
329312 }
@@ -344,24 +327,24 @@ function standardizer(): (key: string, value: any) => any {
344327
345328 if ( stack . indexOf ( value ) !== - 1 ) {
346329 // tslint:disable-next-line:no-parameter-reassignment
347- value = cycleStandardizer . call ( this , key , value ) ;
330+ value = cycleserializer . call ( this , key , value ) ;
348331 }
349332 } else {
350333 stack . push ( value ) ;
351334 }
352335
353- return standardizeValue ( value , key ) ;
336+ return options . normalize ? normalizeValue ( value , key ) : value ;
354337 } ;
355338}
356339
357340/**
358341 * safeNormalize()
359342 *
360- * Creates a copy of the input by applying standardizer function on it and parsing it back to unify the data
343+ * Creates a copy of the input by applying serializer function on it and parsing it back to unify the data
361344 */
362345export function safeNormalize ( input : any ) : any {
363346 try {
364- return JSON . parse ( JSON . stringify ( input , standardizer ( ) ) ) ;
347+ return JSON . parse ( JSON . stringify ( input , serializer ( { normalize : true } ) ) ) ;
365348 } catch ( _oO ) {
366349 return '**non-serializable**' ;
367350 }
0 commit comments