1"use strict"; 2/** 3 * Copyright (c) 650 Industries. 4 * Copyright (c) Meta Platforms, Inc. and affiliates. 5 * 6 * This source code is licensed under the MIT license found in the 7 * LICENSE file in the root directory of this source tree. 8 */ 9Object.defineProperty(exports, "__esModule", { value: true }); 10exports.createStringifySafeWithLimits = void 0; 11/** 12 * Tries to stringify with JSON.stringify and toString, but catches exceptions 13 * (e.g. from circular objects) and always returns a string and never throws. 14 */ 15function createStringifySafeWithLimits(limits) { 16 const { maxDepth = Number.POSITIVE_INFINITY, maxStringLimit = Number.POSITIVE_INFINITY, maxArrayLimit = Number.POSITIVE_INFINITY, maxObjectKeysLimit = Number.POSITIVE_INFINITY, } = limits; 17 const stack = []; 18 function replacer(_key, value) { 19 while (stack.length && this !== stack[0]) { 20 stack.shift(); 21 } 22 if (typeof value === 'string') { 23 const truncatedString = '...(truncated)...'; 24 if (value.length > maxStringLimit + truncatedString.length) { 25 return value.substring(0, maxStringLimit) + truncatedString; 26 } 27 return value; 28 } 29 if (typeof value !== 'object' || value === null) { 30 return value; 31 } 32 let retval = value; 33 if (Array.isArray(value)) { 34 if (stack.length >= maxDepth) { 35 retval = `[ ... array with ${value.length} values ... ]`; 36 } 37 else if (value.length > maxArrayLimit) { 38 retval = value 39 .slice(0, maxArrayLimit) 40 .concat([`... extra ${value.length - maxArrayLimit} values truncated ...`]); 41 } 42 } 43 else { 44 // Add refinement after Array.isArray call. 45 if (typeof value !== 'object') { 46 throw new Error('This was already found earlier'); 47 } 48 const keys = Object.keys(value); 49 if (stack.length >= maxDepth) { 50 retval = `{ ... object with ${keys.length} keys ... }`; 51 } 52 else if (keys.length > maxObjectKeysLimit) { 53 // Return a sample of the keys. 54 retval = {}; 55 for (const k of keys.slice(0, maxObjectKeysLimit)) { 56 retval[k] = value[k]; 57 } 58 const truncatedKey = '...(truncated keys)...'; 59 retval[truncatedKey] = keys.length - maxObjectKeysLimit; 60 } 61 } 62 stack.unshift(retval); 63 return retval; 64 } 65 return function stringifySafe(arg) { 66 if (arg === undefined) { 67 return 'undefined'; 68 } 69 else if (arg === null) { 70 return 'null'; 71 } 72 else if (typeof arg === 'function') { 73 try { 74 return arg.toString(); 75 } 76 catch { 77 return '[function unknown]'; 78 } 79 } 80 else if (arg instanceof Error) { 81 return arg.name + ': ' + arg.message; 82 } 83 else { 84 // Perform a try catch, just in case the object has a circular 85 // reference or stringify throws for some other reason. 86 try { 87 const ret = JSON.stringify(arg, replacer); 88 if (ret === undefined) { 89 return '["' + typeof arg + '" failed to stringify]'; 90 } 91 return ret; 92 } 93 catch { 94 if (typeof arg.toString === 'function') { 95 try { 96 // $FlowFixMe[incompatible-use] : toString shouldn't take any arguments in general. 97 return arg.toString(); 98 } 99 catch { } 100 } 101 } 102 } 103 return '["' + typeof arg + '" failed to stringify]'; 104 }; 105} 106exports.createStringifySafeWithLimits = createStringifySafeWithLimits; 107const stringifySafe = createStringifySafeWithLimits({ 108 maxDepth: 10, 109 maxStringLimit: 100, 110 maxArrayLimit: 50, 111 maxObjectKeysLimit: 50, 112}); 113exports.default = stringifySafe; 114//# sourceMappingURL=index.js.map