function quote ( string ) { return JSON . stringify ( string ) ; } const str = ( key , holder , singleIndent , outerIndent , canonical ) => { const value = holder [ key ] ; switch ( typeof value ) { case "string" : return quote ( value ) ; case "number" : return isFinite ( value ) ? String ( value ) : "null" ; case "boolean" : return String ( value ) ; case "object" : { if ( ! value ) { return "null" ; } const innerIndent = outerIndent + singleIndent ; const partial = [ ] ; let v ; if ( Array . isArray ( value ) || { } . hasOwnProperty . call ( value , "callee" ) ) { const length = value . length ; for ( let i = 0 ; i < length ; i += 1 ) { partial [ i ] = str ( i , value , singleIndent , innerIndent , canonical ) || "null" ; } if ( partial . length === 0 ) { v = "[]" ; } else if ( innerIndent ) { v = "[\n" + innerIndent + partial . join ( ",\n" + innerIndent ) + "\n" + outerIndent + "]" ; } else { v = "[" + partial . join ( "," ) + "]" ; } return v ; } let keys = Object . keys ( value ) ; if ( canonical ) { keys = keys . sort ( ) ; } keys . forEach ( ( k ) => { v = str ( k , value , singleIndent , innerIndent , canonical ) ; if ( v ) { partial . push ( quote ( k ) + ( innerIndent ? ": " : ":" ) + v ) ; } } ) ; if ( partial . length === 0 ) { v = "{}" ; } else if ( innerIndent ) { v = "{\n" + innerIndent + partial . join ( ",\n" + innerIndent ) + "\n" + outerIndent + "}" ; } else { v = "{" + partial . join ( "," ) + "}" ; } return v ; } default : } } ; const canonicalStringify = ( value , options ) => { const allOptions = Object . assign ( { indent : "" , canonical : false , } , options ) ; if ( allOptions . indent === true ) { allOptions . indent = "  " ; } else if ( typeof allOptions . indent === "number" ) { let newIndent = "" ; for ( let i = 0 ; i < allOptions . indent ; i ++ ) { newIndent += " " ; } allOptions . indent = newIndent ; } return str ( "" , { "" : value } , allOptions . indent , "" , allOptions . canonical ) ; } ; export default canonicalStringify ;