@@ -1023,9 +1023,7 @@ function sendfile(res, file, options, callback) {
10231023function stringify ( value , replacer , spaces , escape ) {
10241024 // v8 checks arguments.length for optimizing simple call
10251025 // https://bugs.chromium.org/p/v8/issues/detail?id=4730
1026- var json = replacer || spaces
1027- ? JSON . stringify ( value , replacer , spaces )
1028- : JSON . stringify ( value ) ;
1026+ var json = stringifyWithFallback ( value , replacer , spaces ) ;
10291027
10301028 if ( escape && typeof json === 'string' ) {
10311029 json = json . replace ( / [ < > & ] / g, function ( c ) {
@@ -1045,3 +1043,77 @@ function stringify (value, replacer, spaces, escape) {
10451043
10461044 return json
10471045}
1046+
1047+ function stringifyWithFallback ( value , replacer , spaces ) {
1048+ // v8 checks arguments.length for optimizing simple call
1049+ // https://bugs.chromium.org/p/v8/issues/detail?id=4730
1050+ try {
1051+ return replacer || spaces
1052+ ? JSON . stringify ( value , replacer , spaces )
1053+ : JSON . stringify ( value ) ;
1054+ } catch ( err ) {
1055+ if ( ! isCircularJsonError ( err ) ) {
1056+ throw err ;
1057+ }
1058+
1059+ return JSON . stringify ( value , createCircularReplacer ( replacer ) , spaces ) ;
1060+ }
1061+ }
1062+
1063+ function createCircularReplacer ( replacer ) {
1064+ var stack = [ ] ;
1065+
1066+ return function ( key , value ) {
1067+ var replacement = value ;
1068+
1069+ if ( typeof replacer === "function" ) {
1070+ replacement = replacer . call ( this , key , value ) ;
1071+ } else if (
1072+ Array . isArray ( replacer ) &&
1073+ key !== "" &&
1074+ ! Array . isArray ( this ) &&
1075+ ! hasReplacerKey ( replacer , key )
1076+ ) {
1077+ return undefined ;
1078+ }
1079+
1080+ if ( typeof replacement !== "object" || replacement === null ) {
1081+ return replacement ;
1082+ }
1083+
1084+ while ( stack . length > 0 && stack [ stack . length - 1 ] !== this ) {
1085+ stack . pop ( ) ;
1086+ }
1087+
1088+ if ( stack . indexOf ( replacement ) !== - 1 ) {
1089+ return "[Circular]" ;
1090+ }
1091+
1092+ stack . push ( replacement ) ;
1093+ return replacement ;
1094+ } ;
1095+ }
1096+
1097+ function hasReplacerKey ( replacer , key ) {
1098+ for ( var i = 0 ; i < replacer . length ; i ++ ) {
1099+ var value = replacer [ i ] ;
1100+
1101+ if ( typeof value === "string" || typeof value === "number" ) {
1102+ if ( String ( value ) === key ) {
1103+ return true ;
1104+ }
1105+ } else if (
1106+ typeof value === "object" &&
1107+ value !== null &&
1108+ String ( value ) === key
1109+ ) {
1110+ return true ;
1111+ }
1112+ }
1113+
1114+ return false ;
1115+ }
1116+
1117+ function isCircularJsonError ( err ) {
1118+ return err instanceof TypeError && / c i r c u l a r s t r u c t u r e / i. test ( err . message ) ;
1119+ }
0 commit comments