1
1
import { SentryWrappedFunction } from '@sentry/types' ;
2
2
import { isNaN , isPlainObject , isUndefined } from './is' ;
3
+ import { truncate } from './string' ;
3
4
4
5
/**
5
6
* Just an Error object with arbitrary attributes attached to it.
@@ -11,17 +12,12 @@ interface ExtendedError extends Error {
11
12
/**
12
13
* Serializes the given object into a string.
13
14
* 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
19
15
*
20
16
* @param object A JSON-serializable object.
21
17
* @returns A string containing the serialized object.
22
18
*/
23
19
export function serialize < T > ( object : T ) : string {
24
- return JSON . stringify ( object ) ;
20
+ return JSON . stringify ( object , serializer ( { normalize : false } ) ) ;
25
21
}
26
22
27
23
/**
@@ -105,34 +101,19 @@ function jsonSize(value: any): number {
105
101
106
102
/** JSDoc */
107
103
function 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
-
121
104
const type = Object . prototype . toString . call ( value ) ;
122
105
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
125
110
return '[Object]' ;
126
- }
127
- if ( type === '[object Array]' ) {
111
+ } else if ( type === '[object Array]' ) {
112
+ // Node.js REPL notation
128
113
return '[Array]' ;
114
+ } else {
115
+ return normalizeValue ( value ) as T ;
129
116
}
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 ;
136
117
}
137
118
138
119
/** JSDoc */
@@ -261,13 +242,15 @@ function objectifyError(error: ExtendedError): object {
261
242
}
262
243
263
244
/**
264
- * standardizeValue ()
245
+ * normalizeValue ()
265
246
*
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
269
252
*/
270
- function standardizeValue ( value : any , key : any ) : any {
253
+ function normalizeValue ( value : any , key ? : any ) : any {
271
254
if ( key === 'domain' && typeof value === 'object' && ( value as { _events : any } ) . _events ) {
272
255
return '[Domain]' ;
273
256
}
@@ -305,25 +288,25 @@ function standardizeValue(value: any, key: any): any {
305
288
}
306
289
307
290
if ( typeof value === 'function' ) {
308
- return `[Function] ${ ( value as ( ) => void ) . name || '<unknown-function-name>' } ` ;
291
+ return `[Function: ${ ( value as ( ) => void ) . name || '<unknown-function-name>' } ] ` ;
309
292
}
310
293
311
294
return value ;
312
295
}
313
296
314
297
/**
315
- * standardizer ()
298
+ * serializer ()
316
299
*
317
300
* Remove circular references,
318
301
* translates undefined/NaN values to "[undefined]"/"[NaN]" respectively,
319
302
* and takes care of Error objects serialization
320
303
*/
321
- function standardizer ( ) : ( key : string , value : any ) => any {
304
+ function serializer ( options : { normalize : boolean } = { normalize : true } ) : ( key : string , value : any ) => any {
322
305
const stack : any [ ] = [ ] ;
323
306
const keys : string [ ] = [ ] ;
324
307
325
308
/** recursive */
326
- function cycleStandardizer ( _key : string , value : any ) : any {
309
+ function cycleserializer ( _key : string , value : any ) : any {
327
310
if ( stack [ 0 ] === value ) {
328
311
return '[Circular ~]' ;
329
312
}
@@ -344,24 +327,24 @@ function standardizer(): (key: string, value: any) => any {
344
327
345
328
if ( stack . indexOf ( value ) !== - 1 ) {
346
329
// tslint:disable-next-line:no-parameter-reassignment
347
- value = cycleStandardizer . call ( this , key , value ) ;
330
+ value = cycleserializer . call ( this , key , value ) ;
348
331
}
349
332
} else {
350
333
stack . push ( value ) ;
351
334
}
352
335
353
- return standardizeValue ( value , key ) ;
336
+ return options . normalize ? normalizeValue ( value , key ) : value ;
354
337
} ;
355
338
}
356
339
357
340
/**
358
341
* safeNormalize()
359
342
*
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
361
344
*/
362
345
export function safeNormalize ( input : any ) : any {
363
346
try {
364
- return JSON . parse ( JSON . stringify ( input , standardizer ( ) ) ) ;
347
+ return JSON . parse ( JSON . stringify ( input , serializer ( { normalize : true } ) ) ) ;
365
348
} catch ( _oO ) {
366
349
return '**non-serializable**' ;
367
350
}
0 commit comments