function sprint_go(obj, options, depth) {
  let whitespace = options.hasOwnProperty('whitespace');
  let quote = options.hasOwnProperty('quotes') ? '"' : '';
  let output = '';
  let newline = '';
  let indent = '';
  let outdent = '';

  let type = (typeof obj);
  if (whitespace) {
    newline = '\n';
    for (let i = 0; i < depth - 1; i++) {
      outdent += ' ';
    }
    indent = outdent + ' ';
  }

  // Implementation note: JSON.stringify dies with BigInt and friends, so we do it the hard way.
  if (obj == null) {
    output += 'null';
    return output;
  }
  if (Array.isArray(obj)) {
    output += '[' + newline;
    for (let i = 0; i < obj.length; i++) {
      if (i != 0) {
        output += ',' + newline;
      }
      output += indent;
      output += sprint_go(obj[i], options, depth + 1);
    }
    output += newline + outdent + ']';
    return output;
  }
  switch (type) {
    case 'number':
      output += Number(obj).toString(10);
      return output;
    case 'string':
      output += quote + obj + quote;
      return output;
    case 'boolean':
      output += obj ? 'true' : 'false';
      return output;
    case 'object':
      output += '{' + newline;
      let first = true;
      for (const property in obj) {
        if (!first) {
          output += ',' + newline;
        }
        output += indent;
        output += sprint_go(property, options, depth + 1);
        output += ' : ';
        output += sprint_go(obj[property], options, depth + 1);
        first = false;
      }
      output += newline + outdent + '}';
      return output;
  }
  if (typeof obj.toString == 'function') {
    output += obj.toString();
    return output;
  }
  throw 'Unknown object type for ' + obj;
}
/**
 * Returns a string containing a representation of the object
 *
 * @param {*} obj The object to print
 * @param {*} options Optional boolean parameters.
 *     If this contains a property called "whitespace", you will get pretty printing.
 *     If this contains a property called "quotes", you will get quotation
 *        marks around strings.
 * @param {*} depth The function is recursive; this indicates the levels
 *                  of recursive depth.
 */
Returns a string containing a representation of the object
@param {*} obj The object to print
@param {*} options Optional boolean parameters.
If this contains a property called "whitespace", you will get pretty printing.
If this contains a property called "quotes", you will get quotation
marks around strings.
@param {*} depth The function is recursive; this indicates the levels
of recursive depth.
Returns a string containing a representation of the object @param { * } obj The object to print @param { * } options Optional boolean parameters . If this contains a property called " whitespace " you will get pretty printing . If this contains a property called " quotes " you will get quotation marks around strings . @param { * } depth The function is recursive ; this indicates the levels of recursive depth .
function sprint_go(obj, options, depth) {
  let whitespace = options.hasOwnProperty('whitespace');
  let quote = options.hasOwnProperty('quotes') ? '"' : '';
  let output = '';
  let newline = '';
  let indent = '';
  let outdent = '';
  let type = (typeof obj);
  if (whitespace) {
    newline = '\n';
    for (let i = 0; i < depth - 1; i++) {
      outdent += ' ';
    }
    indent = outdent + ' ';
  }
  if (obj == null) {
    output += 'null';
    return output;
  }
  if (Array.isArray(obj)) {
    output += '[' + newline;
    for (let i = 0; i < obj.length; i++) {
      if (i != 0) {
        output += ',' + newline;
      }
      output += indent;
      output += sprint_go(obj[i], options, depth + 1);
    }
    output += newline + outdent + ']';
    return output;
  }
  switch (type) {
    case 'number':
      output += Number(obj).toString(10);
      return output;
    case 'string':
      output += quote + obj + quote;
      return output;
    case 'boolean':
      output += obj ? 'true' : 'false';
      return output;
    case 'object':
      output += '{' + newline;
      let first = true;
      for (const property in obj) {
        if (!first) {
          output += ',' + newline;
        }
        output += indent;
        output += sprint_go(property, options, depth + 1);
        output += ' : ';
        output += sprint_go(obj[property], options, depth + 1);
        first = false;
      }
      output += newline + outdent + '}';
      return output;
  }
  if (typeof obj.toString == 'function') {
    output += obj.toString();
    return output;
  }
  throw 'Unknown object type for ' + obj;
}
function sprint_go ( obj , options , depth ) { let whitespace = options . hasOwnProperty ( 'whitespace' ) ; let quote = options . hasOwnProperty ( 'quotes' ) ? '"' : '' ; let output = '' ; let newline = '' ; let indent = '' ; let outdent = '' ; let type = ( typeof obj ) ; if ( whitespace ) { newline = '\n' ; for ( let i = 0 ; i < depth - 1 ; i ++ ) { outdent += ' ' ; } indent = outdent + ' ' ; } if ( obj == null ) { output += 'null' ; return output ; } if ( Array . isArray ( obj ) ) { output += '[' + newline ; for ( let i = 0 ; i < obj . length ; i ++ ) { if ( i != 0 ) { output += ',' + newline ; } output += indent ; output += sprint_go ( obj [ i ] , options , depth + 1 ) ; } output += newline + outdent + ']' ; return output ; } switch ( type ) { case 'number' : output += Number ( obj ) . toString ( 10 ) ; return output ; case 'string' : output += quote + obj + quote ; return output ; case 'boolean' : output += obj ? 'true' : 'false' ; return output ; case 'object' : output += '{' + newline ; let first = true ; for ( const property in obj ) { if ( ! first ) { output += ',' + newline ; } output += indent ; output += sprint_go ( property , options , depth + 1 ) ; output += ' : ' ; output += sprint_go ( obj [ property ] , options , depth + 1 ) ; first = false ; } output += newline + outdent + '}' ; return output ; } if ( typeof obj . toString == 'function' ) { output += obj . toString ( ) ; return output ; } throw 'Unknown object type for ' + obj ; }
Returns a string containing a representation of the object
 @param {*} obj The object to print
 @param {*} options Optional boolean parameters.
Returns a string containing a representation of the object @param { * } obj The object to print @param { * } options Optional boolean parameters .
// Implementation note: JSON.stringify dies with BigInt and friends, so we do it the hard way.