@@ -2414,26 +2414,70 @@ namespace ts {
24142414 return output ;
24152415 }
24162416
2417+ /**
2418+ * Serialize an object graph into a JSON string. This is intended only for use on an acyclic graph
2419+ * as the fallback implementation does not check for circular references by default.
2420+ */
24172421 export const stringify : ( value : any ) => string = JSON && JSON . stringify ? JSON . stringify : function stringify ( value : any ) : string {
2422+ if ( Debug . shouldAssert ( AssertionLevel . Aggressive ) ) {
2423+ Debug . assert ( ! hasCycles ( value , [ ] ) , "Detected circular reference before serializing object graph." ) ;
2424+ }
2425+
24182426 return value === undefined ? undefined : stringifyValue ( value ) ;
24192427 } ;
24202428
2421- function stringifyValue ( value : any ) : string {
2429+ function hasCycles ( value : any , stack : any [ ] ) {
24222430 /* tslint:disable:no-null */
2423- return value === null ? "null" // explicit test for `null` as `typeof null` is "object"
2424- : typeof value === "string" ? `"${ escapeString ( value ) } "`
2425- : typeof value === "number" ? String ( value )
2431+ if ( typeof value !== "object" || value === null ) {
2432+ return false ;
2433+ }
2434+ /* tslint:enable:no-null */
2435+
2436+ if ( stack . lastIndexOf ( value ) !== - 1 ) {
2437+ return true ;
2438+ }
2439+
2440+ stack . push ( value ) ;
2441+
2442+ if ( isArray ( value ) ) {
2443+ for ( const entry of value ) {
2444+ if ( hasCycles ( entry , stack ) ) {
2445+ return true ;
2446+ }
2447+ }
2448+ }
2449+ else {
2450+ for ( const key in value ) {
2451+ if ( hasProperty ( value , key ) && hasCycles ( value [ key ] , stack ) ) {
2452+ return true ;
2453+ }
2454+ }
2455+ }
2456+
2457+ stack . pop ( ) ;
2458+ return false ;
2459+ }
2460+
2461+ function stringifyValue ( value : any ) : string {
2462+ return typeof value === "string" ? `"${ escapeString ( value ) } "`
2463+ : typeof value === "number" ? isFinite ( value ) ? String ( value ) : "null"
24262464 : typeof value === "boolean" ? value ? "true" : "false"
2427- : isArray ( value ) ? `[${ reduceLeft ( value , stringifyElement , "" ) } ]`
2428- : typeof value === "object" ? `{${ reduceProperties ( value , stringifyProperty , "" ) } }`
2465+ : typeof value === "object" ? isArray ( value ) ? stringifyArray ( value ) : stringifyObject ( value )
24292466 : /*fallback*/ "null" ;
2430- /* tslint:enable:no-null */
2467+ }
2468+
2469+ function stringifyArray ( value : any ) {
2470+ return `[${ reduceLeft ( value , stringifyElement , "" ) } ]` ;
24312471 }
24322472
24332473 function stringifyElement ( memo : string , value : any ) {
24342474 return ( memo ? memo + "," : memo ) + stringifyValue ( value ) ;
24352475 }
24362476
2477+ function stringifyObject ( value : any ) {
2478+ return value ? `{${ reduceProperties ( value , stringifyProperty , "" ) } }` : "null" ;
2479+ }
2480+
24372481 function stringifyProperty ( memo : string , value : any , key : string ) {
24382482 return value === undefined || typeof value === "function" ? memo
24392483 : ( memo ? memo + "," : memo ) + `"${ escapeString ( key ) } ":${ stringifyValue ( value ) } ` ;
0 commit comments