@@ -189,6 +189,10 @@ export function endsWith(input: string, suffix: string): boolean {
189
189
*/
190
190
export function prune ( value : unknown , depth : number = 10 ) : unknown {
191
191
function isUnsupportedType ( value : unknown ) : boolean {
192
+ if ( value === null || value === undefined ) {
193
+ return false ;
194
+ }
195
+
192
196
switch ( typeof value ) {
193
197
case "function" :
194
198
return true ;
@@ -205,6 +209,11 @@ export function prune(value: unknown, depth: number = 10): unknown {
205
209
return true ;
206
210
}
207
211
212
+ // Check for buffer;
213
+ if ( "writeBigInt64LE" in value ) {
214
+ return true ;
215
+ }
216
+
208
217
break ;
209
218
}
210
219
@@ -254,35 +263,47 @@ export function prune(value: unknown, depth: number = 10): unknown {
254
263
return value ;
255
264
}
256
265
266
+ if ( currentDepth > maxDepth ) {
267
+ return undefined ;
268
+ }
269
+
257
270
if ( isUnsupportedType ( value ) ) {
258
271
return undefined ;
259
272
}
260
273
261
- if ( typeof value === "object" ) {
262
- const normalizedValue = normalizeValue ( value ) ;
274
+ const normalizedValue = normalizeValue ( value ) ;
275
+ if ( typeof normalizedValue === "object" ) {
276
+ if ( normalizedValue instanceof Date ) {
277
+ return normalizedValue ;
278
+ }
279
+
263
280
if ( Array . isArray ( normalizedValue ) ) {
264
- return currentDepth < maxDepth
265
- ? normalizedValue . map ( e => pruneImpl ( e , maxDepth , currentDepth + 1 , seen ) )
266
- : [ ] ;
281
+ return normalizedValue . map ( e => pruneImpl ( e , maxDepth , currentDepth + 1 , seen ) ) ;
267
282
}
268
283
269
284
// Check for circular references
270
- if ( currentDepth >= maxDepth || seen . has ( value ) ) {
271
- return undefined ;
272
- }
285
+ if ( Object . prototype . toString . call ( normalizedValue ) === "[object Object]" ) {
286
+ if ( seen . has ( normalizedValue as object ) ) {
287
+ return undefined ;
288
+ }
273
289
274
- seen . add ( value ) ;
290
+ seen . add ( normalizedValue as object ) ;
291
+ }
275
292
276
293
const result : Record < PropertyKey , unknown > = { } ;
277
- for ( const key of getAllKeysConditionally ( value , true , true , false , true , true , false , true ) ) {
294
+ for ( const key in value ) {
278
295
const val = ( value as { [ index : PropertyKey ] : unknown } ) [ key ] ;
279
296
result [ key ] = pruneImpl ( val , maxDepth , currentDepth + 1 , seen ) ;
280
297
}
281
298
282
299
return result ;
283
300
}
284
301
285
- return value ;
302
+ return normalizedValue ;
303
+ }
304
+
305
+ if ( depth < 0 ) {
306
+ return undefined ;
286
307
}
287
308
288
309
return pruneImpl ( value , depth , 0 ) ;
@@ -304,38 +325,38 @@ export function stringify(data: unknown, exclusions?: string[], maxDepth: number
304
325
}
305
326
306
327
// https://stackoverflow.com/questions/8024149/is-it-possible-to-get-the-non-enumerable-inherited-property-names-of-an-object
307
- function getAllKeysConditionally ( obj : object , includeSelf = true , includePrototypeChain = true , includeTop = false , includeEnumerables = true , includeNonenumerables = true , includeStrings = true , includeSymbols = true ) {
308
-
309
- // Boolean (mini-)functions to determine unknown given key's eligibility:
310
- const isEnumerable = ( obj : object , key : PropertyKey ) => Object . propertyIsEnumerable . call ( obj , key ) ;
311
- const isString = ( key : PropertyKey ) => typeof key === 'string' ;
312
- const isSymbol = ( key : PropertyKey ) => typeof key === 'symbol' ;
313
- const includeBasedOnEnumerability = ( obj : object , key : PropertyKey ) => ( includeEnumerables && isEnumerable ( obj , key ) ) || ( includeNonenumerables && ! isEnumerable ( obj , key ) ) ;
314
- const includeBasedOnKeyType = ( key : PropertyKey ) => ( includeStrings && isString ( key ) ) || ( includeSymbols && isSymbol ( key ) ) ;
315
- const include = ( obj : object , key : PropertyKey ) => includeBasedOnEnumerability ( obj , key ) && includeBasedOnKeyType ( key ) ;
316
- const notYetRetrieved = ( keys : PropertyKey [ ] , key : PropertyKey ) => ! keys . includes ( key ) ;
317
-
318
- // filter function putting all the above together:
319
- const filterFn = ( key : PropertyKey ) => notYetRetrieved ( keys , key ) && include ( obj , key ) ;
320
-
321
- // conditional chooses one of two functions to determine whether to exclude the top level or not:
322
- const stopFn = includeTop ? ( ( obj : unknown ) => obj === null ) : ( ( obj : unknown ) => Object . getPrototypeOf ( obj ) === null ) ;
323
-
324
- // and now the loop to collect and filter everything:
325
- let keys : PropertyKey [ ] = [ ] ;
326
- while ( ! stopFn ( obj ) ) {
327
- if ( includeSelf ) {
328
- const ownKeys = Reflect . ownKeys ( obj ) . filter ( filterFn ) ;
329
- keys = keys . concat ( ownKeys ) ;
330
- }
331
- if ( ! includePrototypeChain ) { break ; }
332
- else {
333
- includeSelf = true ;
334
- obj = Object . getPrototypeOf ( obj ) ;
335
- }
336
- }
337
- return keys ;
338
- }
328
+ // function getAllKeysConditionally(obj: object, includeSelf = true, includePrototypeChain = true, includeTop = false, includeEnumerables = true, includeNonenumerables = true, includeStrings = true, includeSymbols = true) {
329
+ //
330
+ // // Boolean (mini-)functions to determine unknown given key's eligibility:
331
+ // const isEnumerable = (obj: object, key: PropertyKey) => Object.propertyIsEnumerable.call(obj, key);
332
+ // const isString = (key: PropertyKey) => typeof key === 'string';
333
+ // const isSymbol = (key: PropertyKey) => typeof key === 'symbol';
334
+ // const includeBasedOnEnumerability = (obj: object, key: PropertyKey) => (includeEnumerables && isEnumerable(obj, key)) || (includeNonenumerables && !isEnumerable(obj, key));
335
+ // const includeBasedOnKeyType = (key: PropertyKey) => (includeStrings && isString(key)) || (includeSymbols && isSymbol(key));
336
+ // const include = (obj: object, key: PropertyKey) => includeBasedOnEnumerability(obj, key) && includeBasedOnKeyType(key);
337
+ // const notYetRetrieved = (keys: PropertyKey[], key: PropertyKey) => !keys.includes(key);
338
+ //
339
+ // // filter function putting all the above together:
340
+ // const filterFn = (key: PropertyKey) => notYetRetrieved(keys, key) && include(obj, key);
341
+ //
342
+ // // conditional chooses one of two functions to determine whether to exclude the top level or not:
343
+ // const stopFn = includeTop ? ((obj: unknown) => obj === null) : ((obj: unknown) => Object.getPrototypeOf(obj) === null);
344
+ //
345
+ // // and now the loop to collect and filter everything:
346
+ // let keys: PropertyKey[] = [];
347
+ // while (!stopFn(obj)) {
348
+ // if (includeSelf) {
349
+ // const ownKeys = Reflect.ownKeys(obj).filter(filterFn);
350
+ // keys = keys.concat(ownKeys);
351
+ // }
352
+ // if (!includePrototypeChain) { break; }
353
+ // else {
354
+ // includeSelf = true;
355
+ // obj = Object.getPrototypeOf(obj);
356
+ // }
357
+ // }
358
+ // return keys;
359
+ // }
339
360
340
361
// export function stringify(data: unknown, exclusions?: string[], maxDepth?: number = Infinity): string | undefined {
341
362
// function stringifyImpl(obj: unknown, excludedKeys: string[], maxDepth?: number = Infinity, currentDepth: number, cache: WeakSet): string | undefined {
0 commit comments