626 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			626 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
'use strict'
 | 
						|
 | 
						|
const { hasOwnProperty } = Object.prototype
 | 
						|
 | 
						|
const stringify = configure()
 | 
						|
 | 
						|
// @ts-expect-error
 | 
						|
stringify.configure = configure
 | 
						|
// @ts-expect-error
 | 
						|
stringify.stringify = stringify
 | 
						|
 | 
						|
// @ts-expect-error
 | 
						|
stringify.default = stringify
 | 
						|
 | 
						|
// @ts-expect-error used for named export
 | 
						|
exports.stringify = stringify
 | 
						|
// @ts-expect-error used for named export
 | 
						|
exports.configure = configure
 | 
						|
 | 
						|
module.exports = stringify
 | 
						|
 | 
						|
// eslint-disable-next-line no-control-regex
 | 
						|
const strEscapeSequencesRegExp = /[\u0000-\u001f\u0022\u005c\ud800-\udfff]/
 | 
						|
 | 
						|
// Escape C0 control characters, double quotes, the backslash and every code
 | 
						|
// unit with a numeric value in the inclusive range 0xD800 to 0xDFFF.
 | 
						|
function strEscape (str) {
 | 
						|
  // Some magic numbers that worked out fine while benchmarking with v8 8.0
 | 
						|
  if (str.length < 5000 && !strEscapeSequencesRegExp.test(str)) {
 | 
						|
    return `"${str}"`
 | 
						|
  }
 | 
						|
  return JSON.stringify(str)
 | 
						|
}
 | 
						|
 | 
						|
function sort (array, comparator) {
 | 
						|
  // Insertion sort is very efficient for small input sizes, but it has a bad
 | 
						|
  // worst case complexity. Thus, use native array sort for bigger values.
 | 
						|
  if (array.length > 2e2 || comparator) {
 | 
						|
    return array.sort(comparator)
 | 
						|
  }
 | 
						|
  for (let i = 1; i < array.length; i++) {
 | 
						|
    const currentValue = array[i]
 | 
						|
    let position = i
 | 
						|
    while (position !== 0 && array[position - 1] > currentValue) {
 | 
						|
      array[position] = array[position - 1]
 | 
						|
      position--
 | 
						|
    }
 | 
						|
    array[position] = currentValue
 | 
						|
  }
 | 
						|
  return array
 | 
						|
}
 | 
						|
 | 
						|
const typedArrayPrototypeGetSymbolToStringTag =
 | 
						|
  Object.getOwnPropertyDescriptor(
 | 
						|
    Object.getPrototypeOf(
 | 
						|
      Object.getPrototypeOf(
 | 
						|
        new Int8Array()
 | 
						|
      )
 | 
						|
    ),
 | 
						|
    Symbol.toStringTag
 | 
						|
  ).get
 | 
						|
 | 
						|
function isTypedArrayWithEntries (value) {
 | 
						|
  return typedArrayPrototypeGetSymbolToStringTag.call(value) !== undefined && value.length !== 0
 | 
						|
}
 | 
						|
 | 
						|
function stringifyTypedArray (array, separator, maximumBreadth) {
 | 
						|
  if (array.length < maximumBreadth) {
 | 
						|
    maximumBreadth = array.length
 | 
						|
  }
 | 
						|
  const whitespace = separator === ',' ? '' : ' '
 | 
						|
  let res = `"0":${whitespace}${array[0]}`
 | 
						|
  for (let i = 1; i < maximumBreadth; i++) {
 | 
						|
    res += `${separator}"${i}":${whitespace}${array[i]}`
 | 
						|
  }
 | 
						|
  return res
 | 
						|
}
 | 
						|
 | 
						|
function getCircularValueOption (options) {
 | 
						|
  if (hasOwnProperty.call(options, 'circularValue')) {
 | 
						|
    const circularValue = options.circularValue
 | 
						|
    if (typeof circularValue === 'string') {
 | 
						|
      return `"${circularValue}"`
 | 
						|
    }
 | 
						|
    if (circularValue == null) {
 | 
						|
      return circularValue
 | 
						|
    }
 | 
						|
    if (circularValue === Error || circularValue === TypeError) {
 | 
						|
      return {
 | 
						|
        toString () {
 | 
						|
          throw new TypeError('Converting circular structure to JSON')
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    throw new TypeError('The "circularValue" argument must be of type string or the value null or undefined')
 | 
						|
  }
 | 
						|
  return '"[Circular]"'
 | 
						|
}
 | 
						|
 | 
						|
function getDeterministicOption (options) {
 | 
						|
  let value
 | 
						|
  if (hasOwnProperty.call(options, 'deterministic')) {
 | 
						|
    value = options.deterministic
 | 
						|
    if (typeof value !== 'boolean' && typeof value !== 'function') {
 | 
						|
      throw new TypeError('The "deterministic" argument must be of type boolean or comparator function')
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return value === undefined ? true : value
 | 
						|
}
 | 
						|
 | 
						|
function getBooleanOption (options, key) {
 | 
						|
  let value
 | 
						|
  if (hasOwnProperty.call(options, key)) {
 | 
						|
    value = options[key]
 | 
						|
    if (typeof value !== 'boolean') {
 | 
						|
      throw new TypeError(`The "${key}" argument must be of type boolean`)
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return value === undefined ? true : value
 | 
						|
}
 | 
						|
 | 
						|
function getPositiveIntegerOption (options, key) {
 | 
						|
  let value
 | 
						|
  if (hasOwnProperty.call(options, key)) {
 | 
						|
    value = options[key]
 | 
						|
    if (typeof value !== 'number') {
 | 
						|
      throw new TypeError(`The "${key}" argument must be of type number`)
 | 
						|
    }
 | 
						|
    if (!Number.isInteger(value)) {
 | 
						|
      throw new TypeError(`The "${key}" argument must be an integer`)
 | 
						|
    }
 | 
						|
    if (value < 1) {
 | 
						|
      throw new RangeError(`The "${key}" argument must be >= 1`)
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return value === undefined ? Infinity : value
 | 
						|
}
 | 
						|
 | 
						|
function getItemCount (number) {
 | 
						|
  if (number === 1) {
 | 
						|
    return '1 item'
 | 
						|
  }
 | 
						|
  return `${number} items`
 | 
						|
}
 | 
						|
 | 
						|
function getUniqueReplacerSet (replacerArray) {
 | 
						|
  const replacerSet = new Set()
 | 
						|
  for (const value of replacerArray) {
 | 
						|
    if (typeof value === 'string' || typeof value === 'number') {
 | 
						|
      replacerSet.add(String(value))
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return replacerSet
 | 
						|
}
 | 
						|
 | 
						|
function getStrictOption (options) {
 | 
						|
  if (hasOwnProperty.call(options, 'strict')) {
 | 
						|
    const value = options.strict
 | 
						|
    if (typeof value !== 'boolean') {
 | 
						|
      throw new TypeError('The "strict" argument must be of type boolean')
 | 
						|
    }
 | 
						|
    if (value) {
 | 
						|
      return (value) => {
 | 
						|
        let message = `Object can not safely be stringified. Received type ${typeof value}`
 | 
						|
        if (typeof value !== 'function') message += ` (${value.toString()})`
 | 
						|
        throw new Error(message)
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function configure (options) {
 | 
						|
  options = { ...options }
 | 
						|
  const fail = getStrictOption(options)
 | 
						|
  if (fail) {
 | 
						|
    if (options.bigint === undefined) {
 | 
						|
      options.bigint = false
 | 
						|
    }
 | 
						|
    if (!('circularValue' in options)) {
 | 
						|
      options.circularValue = Error
 | 
						|
    }
 | 
						|
  }
 | 
						|
  const circularValue = getCircularValueOption(options)
 | 
						|
  const bigint = getBooleanOption(options, 'bigint')
 | 
						|
  const deterministic = getDeterministicOption(options)
 | 
						|
  const comparator = typeof deterministic === 'function' ? deterministic : undefined
 | 
						|
  const maximumDepth = getPositiveIntegerOption(options, 'maximumDepth')
 | 
						|
  const maximumBreadth = getPositiveIntegerOption(options, 'maximumBreadth')
 | 
						|
 | 
						|
  function stringifyFnReplacer (key, parent, stack, replacer, spacer, indentation) {
 | 
						|
    let value = parent[key]
 | 
						|
 | 
						|
    if (typeof value === 'object' && value !== null && typeof value.toJSON === 'function') {
 | 
						|
      value = value.toJSON(key)
 | 
						|
    }
 | 
						|
    value = replacer.call(parent, key, value)
 | 
						|
 | 
						|
    switch (typeof value) {
 | 
						|
      case 'string':
 | 
						|
        return strEscape(value)
 | 
						|
      case 'object': {
 | 
						|
        if (value === null) {
 | 
						|
          return 'null'
 | 
						|
        }
 | 
						|
        if (stack.indexOf(value) !== -1) {
 | 
						|
          return circularValue
 | 
						|
        }
 | 
						|
 | 
						|
        let res = ''
 | 
						|
        let join = ','
 | 
						|
        const originalIndentation = indentation
 | 
						|
 | 
						|
        if (Array.isArray(value)) {
 | 
						|
          if (value.length === 0) {
 | 
						|
            return '[]'
 | 
						|
          }
 | 
						|
          if (maximumDepth < stack.length + 1) {
 | 
						|
            return '"[Array]"'
 | 
						|
          }
 | 
						|
          stack.push(value)
 | 
						|
          if (spacer !== '') {
 | 
						|
            indentation += spacer
 | 
						|
            res += `\n${indentation}`
 | 
						|
            join = `,\n${indentation}`
 | 
						|
          }
 | 
						|
          const maximumValuesToStringify = Math.min(value.length, maximumBreadth)
 | 
						|
          let i = 0
 | 
						|
          for (; i < maximumValuesToStringify - 1; i++) {
 | 
						|
            const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation)
 | 
						|
            res += tmp !== undefined ? tmp : 'null'
 | 
						|
            res += join
 | 
						|
          }
 | 
						|
          const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation)
 | 
						|
          res += tmp !== undefined ? tmp : 'null'
 | 
						|
          if (value.length - 1 > maximumBreadth) {
 | 
						|
            const removedKeys = value.length - maximumBreadth - 1
 | 
						|
            res += `${join}"... ${getItemCount(removedKeys)} not stringified"`
 | 
						|
          }
 | 
						|
          if (spacer !== '') {
 | 
						|
            res += `\n${originalIndentation}`
 | 
						|
          }
 | 
						|
          stack.pop()
 | 
						|
          return `[${res}]`
 | 
						|
        }
 | 
						|
 | 
						|
        let keys = Object.keys(value)
 | 
						|
        const keyLength = keys.length
 | 
						|
        if (keyLength === 0) {
 | 
						|
          return '{}'
 | 
						|
        }
 | 
						|
        if (maximumDepth < stack.length + 1) {
 | 
						|
          return '"[Object]"'
 | 
						|
        }
 | 
						|
        let whitespace = ''
 | 
						|
        let separator = ''
 | 
						|
        if (spacer !== '') {
 | 
						|
          indentation += spacer
 | 
						|
          join = `,\n${indentation}`
 | 
						|
          whitespace = ' '
 | 
						|
        }
 | 
						|
        const maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth)
 | 
						|
        if (deterministic && !isTypedArrayWithEntries(value)) {
 | 
						|
          keys = sort(keys, comparator)
 | 
						|
        }
 | 
						|
        stack.push(value)
 | 
						|
        for (let i = 0; i < maximumPropertiesToStringify; i++) {
 | 
						|
          const key = keys[i]
 | 
						|
          const tmp = stringifyFnReplacer(key, value, stack, replacer, spacer, indentation)
 | 
						|
          if (tmp !== undefined) {
 | 
						|
            res += `${separator}${strEscape(key)}:${whitespace}${tmp}`
 | 
						|
            separator = join
 | 
						|
          }
 | 
						|
        }
 | 
						|
        if (keyLength > maximumBreadth) {
 | 
						|
          const removedKeys = keyLength - maximumBreadth
 | 
						|
          res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`
 | 
						|
          separator = join
 | 
						|
        }
 | 
						|
        if (spacer !== '' && separator.length > 1) {
 | 
						|
          res = `\n${indentation}${res}\n${originalIndentation}`
 | 
						|
        }
 | 
						|
        stack.pop()
 | 
						|
        return `{${res}}`
 | 
						|
      }
 | 
						|
      case 'number':
 | 
						|
        return isFinite(value) ? String(value) : fail ? fail(value) : 'null'
 | 
						|
      case 'boolean':
 | 
						|
        return value === true ? 'true' : 'false'
 | 
						|
      case 'undefined':
 | 
						|
        return undefined
 | 
						|
      case 'bigint':
 | 
						|
        if (bigint) {
 | 
						|
          return String(value)
 | 
						|
        }
 | 
						|
        // fallthrough
 | 
						|
      default:
 | 
						|
        return fail ? fail(value) : undefined
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function stringifyArrayReplacer (key, value, stack, replacer, spacer, indentation) {
 | 
						|
    if (typeof value === 'object' && value !== null && typeof value.toJSON === 'function') {
 | 
						|
      value = value.toJSON(key)
 | 
						|
    }
 | 
						|
 | 
						|
    switch (typeof value) {
 | 
						|
      case 'string':
 | 
						|
        return strEscape(value)
 | 
						|
      case 'object': {
 | 
						|
        if (value === null) {
 | 
						|
          return 'null'
 | 
						|
        }
 | 
						|
        if (stack.indexOf(value) !== -1) {
 | 
						|
          return circularValue
 | 
						|
        }
 | 
						|
 | 
						|
        const originalIndentation = indentation
 | 
						|
        let res = ''
 | 
						|
        let join = ','
 | 
						|
 | 
						|
        if (Array.isArray(value)) {
 | 
						|
          if (value.length === 0) {
 | 
						|
            return '[]'
 | 
						|
          }
 | 
						|
          if (maximumDepth < stack.length + 1) {
 | 
						|
            return '"[Array]"'
 | 
						|
          }
 | 
						|
          stack.push(value)
 | 
						|
          if (spacer !== '') {
 | 
						|
            indentation += spacer
 | 
						|
            res += `\n${indentation}`
 | 
						|
            join = `,\n${indentation}`
 | 
						|
          }
 | 
						|
          const maximumValuesToStringify = Math.min(value.length, maximumBreadth)
 | 
						|
          let i = 0
 | 
						|
          for (; i < maximumValuesToStringify - 1; i++) {
 | 
						|
            const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation)
 | 
						|
            res += tmp !== undefined ? tmp : 'null'
 | 
						|
            res += join
 | 
						|
          }
 | 
						|
          const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation)
 | 
						|
          res += tmp !== undefined ? tmp : 'null'
 | 
						|
          if (value.length - 1 > maximumBreadth) {
 | 
						|
            const removedKeys = value.length - maximumBreadth - 1
 | 
						|
            res += `${join}"... ${getItemCount(removedKeys)} not stringified"`
 | 
						|
          }
 | 
						|
          if (spacer !== '') {
 | 
						|
            res += `\n${originalIndentation}`
 | 
						|
          }
 | 
						|
          stack.pop()
 | 
						|
          return `[${res}]`
 | 
						|
        }
 | 
						|
        stack.push(value)
 | 
						|
        let whitespace = ''
 | 
						|
        if (spacer !== '') {
 | 
						|
          indentation += spacer
 | 
						|
          join = `,\n${indentation}`
 | 
						|
          whitespace = ' '
 | 
						|
        }
 | 
						|
        let separator = ''
 | 
						|
        for (const key of replacer) {
 | 
						|
          const tmp = stringifyArrayReplacer(key, value[key], stack, replacer, spacer, indentation)
 | 
						|
          if (tmp !== undefined) {
 | 
						|
            res += `${separator}${strEscape(key)}:${whitespace}${tmp}`
 | 
						|
            separator = join
 | 
						|
          }
 | 
						|
        }
 | 
						|
        if (spacer !== '' && separator.length > 1) {
 | 
						|
          res = `\n${indentation}${res}\n${originalIndentation}`
 | 
						|
        }
 | 
						|
        stack.pop()
 | 
						|
        return `{${res}}`
 | 
						|
      }
 | 
						|
      case 'number':
 | 
						|
        return isFinite(value) ? String(value) : fail ? fail(value) : 'null'
 | 
						|
      case 'boolean':
 | 
						|
        return value === true ? 'true' : 'false'
 | 
						|
      case 'undefined':
 | 
						|
        return undefined
 | 
						|
      case 'bigint':
 | 
						|
        if (bigint) {
 | 
						|
          return String(value)
 | 
						|
        }
 | 
						|
        // fallthrough
 | 
						|
      default:
 | 
						|
        return fail ? fail(value) : undefined
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function stringifyIndent (key, value, stack, spacer, indentation) {
 | 
						|
    switch (typeof value) {
 | 
						|
      case 'string':
 | 
						|
        return strEscape(value)
 | 
						|
      case 'object': {
 | 
						|
        if (value === null) {
 | 
						|
          return 'null'
 | 
						|
        }
 | 
						|
        if (typeof value.toJSON === 'function') {
 | 
						|
          value = value.toJSON(key)
 | 
						|
          // Prevent calling `toJSON` again.
 | 
						|
          if (typeof value !== 'object') {
 | 
						|
            return stringifyIndent(key, value, stack, spacer, indentation)
 | 
						|
          }
 | 
						|
          if (value === null) {
 | 
						|
            return 'null'
 | 
						|
          }
 | 
						|
        }
 | 
						|
        if (stack.indexOf(value) !== -1) {
 | 
						|
          return circularValue
 | 
						|
        }
 | 
						|
        const originalIndentation = indentation
 | 
						|
 | 
						|
        if (Array.isArray(value)) {
 | 
						|
          if (value.length === 0) {
 | 
						|
            return '[]'
 | 
						|
          }
 | 
						|
          if (maximumDepth < stack.length + 1) {
 | 
						|
            return '"[Array]"'
 | 
						|
          }
 | 
						|
          stack.push(value)
 | 
						|
          indentation += spacer
 | 
						|
          let res = `\n${indentation}`
 | 
						|
          const join = `,\n${indentation}`
 | 
						|
          const maximumValuesToStringify = Math.min(value.length, maximumBreadth)
 | 
						|
          let i = 0
 | 
						|
          for (; i < maximumValuesToStringify - 1; i++) {
 | 
						|
            const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation)
 | 
						|
            res += tmp !== undefined ? tmp : 'null'
 | 
						|
            res += join
 | 
						|
          }
 | 
						|
          const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation)
 | 
						|
          res += tmp !== undefined ? tmp : 'null'
 | 
						|
          if (value.length - 1 > maximumBreadth) {
 | 
						|
            const removedKeys = value.length - maximumBreadth - 1
 | 
						|
            res += `${join}"... ${getItemCount(removedKeys)} not stringified"`
 | 
						|
          }
 | 
						|
          res += `\n${originalIndentation}`
 | 
						|
          stack.pop()
 | 
						|
          return `[${res}]`
 | 
						|
        }
 | 
						|
 | 
						|
        let keys = Object.keys(value)
 | 
						|
        const keyLength = keys.length
 | 
						|
        if (keyLength === 0) {
 | 
						|
          return '{}'
 | 
						|
        }
 | 
						|
        if (maximumDepth < stack.length + 1) {
 | 
						|
          return '"[Object]"'
 | 
						|
        }
 | 
						|
        indentation += spacer
 | 
						|
        const join = `,\n${indentation}`
 | 
						|
        let res = ''
 | 
						|
        let separator = ''
 | 
						|
        let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth)
 | 
						|
        if (isTypedArrayWithEntries(value)) {
 | 
						|
          res += stringifyTypedArray(value, join, maximumBreadth)
 | 
						|
          keys = keys.slice(value.length)
 | 
						|
          maximumPropertiesToStringify -= value.length
 | 
						|
          separator = join
 | 
						|
        }
 | 
						|
        if (deterministic) {
 | 
						|
          keys = sort(keys, comparator)
 | 
						|
        }
 | 
						|
        stack.push(value)
 | 
						|
        for (let i = 0; i < maximumPropertiesToStringify; i++) {
 | 
						|
          const key = keys[i]
 | 
						|
          const tmp = stringifyIndent(key, value[key], stack, spacer, indentation)
 | 
						|
          if (tmp !== undefined) {
 | 
						|
            res += `${separator}${strEscape(key)}: ${tmp}`
 | 
						|
            separator = join
 | 
						|
          }
 | 
						|
        }
 | 
						|
        if (keyLength > maximumBreadth) {
 | 
						|
          const removedKeys = keyLength - maximumBreadth
 | 
						|
          res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`
 | 
						|
          separator = join
 | 
						|
        }
 | 
						|
        if (separator !== '') {
 | 
						|
          res = `\n${indentation}${res}\n${originalIndentation}`
 | 
						|
        }
 | 
						|
        stack.pop()
 | 
						|
        return `{${res}}`
 | 
						|
      }
 | 
						|
      case 'number':
 | 
						|
        return isFinite(value) ? String(value) : fail ? fail(value) : 'null'
 | 
						|
      case 'boolean':
 | 
						|
        return value === true ? 'true' : 'false'
 | 
						|
      case 'undefined':
 | 
						|
        return undefined
 | 
						|
      case 'bigint':
 | 
						|
        if (bigint) {
 | 
						|
          return String(value)
 | 
						|
        }
 | 
						|
        // fallthrough
 | 
						|
      default:
 | 
						|
        return fail ? fail(value) : undefined
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function stringifySimple (key, value, stack) {
 | 
						|
    switch (typeof value) {
 | 
						|
      case 'string':
 | 
						|
        return strEscape(value)
 | 
						|
      case 'object': {
 | 
						|
        if (value === null) {
 | 
						|
          return 'null'
 | 
						|
        }
 | 
						|
        if (typeof value.toJSON === 'function') {
 | 
						|
          value = value.toJSON(key)
 | 
						|
          // Prevent calling `toJSON` again
 | 
						|
          if (typeof value !== 'object') {
 | 
						|
            return stringifySimple(key, value, stack)
 | 
						|
          }
 | 
						|
          if (value === null) {
 | 
						|
            return 'null'
 | 
						|
          }
 | 
						|
        }
 | 
						|
        if (stack.indexOf(value) !== -1) {
 | 
						|
          return circularValue
 | 
						|
        }
 | 
						|
 | 
						|
        let res = ''
 | 
						|
 | 
						|
        const hasLength = value.length !== undefined
 | 
						|
        if (hasLength && Array.isArray(value)) {
 | 
						|
          if (value.length === 0) {
 | 
						|
            return '[]'
 | 
						|
          }
 | 
						|
          if (maximumDepth < stack.length + 1) {
 | 
						|
            return '"[Array]"'
 | 
						|
          }
 | 
						|
          stack.push(value)
 | 
						|
          const maximumValuesToStringify = Math.min(value.length, maximumBreadth)
 | 
						|
          let i = 0
 | 
						|
          for (; i < maximumValuesToStringify - 1; i++) {
 | 
						|
            const tmp = stringifySimple(String(i), value[i], stack)
 | 
						|
            res += tmp !== undefined ? tmp : 'null'
 | 
						|
            res += ','
 | 
						|
          }
 | 
						|
          const tmp = stringifySimple(String(i), value[i], stack)
 | 
						|
          res += tmp !== undefined ? tmp : 'null'
 | 
						|
          if (value.length - 1 > maximumBreadth) {
 | 
						|
            const removedKeys = value.length - maximumBreadth - 1
 | 
						|
            res += `,"... ${getItemCount(removedKeys)} not stringified"`
 | 
						|
          }
 | 
						|
          stack.pop()
 | 
						|
          return `[${res}]`
 | 
						|
        }
 | 
						|
 | 
						|
        let keys = Object.keys(value)
 | 
						|
        const keyLength = keys.length
 | 
						|
        if (keyLength === 0) {
 | 
						|
          return '{}'
 | 
						|
        }
 | 
						|
        if (maximumDepth < stack.length + 1) {
 | 
						|
          return '"[Object]"'
 | 
						|
        }
 | 
						|
        let separator = ''
 | 
						|
        let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth)
 | 
						|
        if (hasLength && isTypedArrayWithEntries(value)) {
 | 
						|
          res += stringifyTypedArray(value, ',', maximumBreadth)
 | 
						|
          keys = keys.slice(value.length)
 | 
						|
          maximumPropertiesToStringify -= value.length
 | 
						|
          separator = ','
 | 
						|
        }
 | 
						|
        if (deterministic) {
 | 
						|
          keys = sort(keys, comparator)
 | 
						|
        }
 | 
						|
        stack.push(value)
 | 
						|
        for (let i = 0; i < maximumPropertiesToStringify; i++) {
 | 
						|
          const key = keys[i]
 | 
						|
          const tmp = stringifySimple(key, value[key], stack)
 | 
						|
          if (tmp !== undefined) {
 | 
						|
            res += `${separator}${strEscape(key)}:${tmp}`
 | 
						|
            separator = ','
 | 
						|
          }
 | 
						|
        }
 | 
						|
        if (keyLength > maximumBreadth) {
 | 
						|
          const removedKeys = keyLength - maximumBreadth
 | 
						|
          res += `${separator}"...":"${getItemCount(removedKeys)} not stringified"`
 | 
						|
        }
 | 
						|
        stack.pop()
 | 
						|
        return `{${res}}`
 | 
						|
      }
 | 
						|
      case 'number':
 | 
						|
        return isFinite(value) ? String(value) : fail ? fail(value) : 'null'
 | 
						|
      case 'boolean':
 | 
						|
        return value === true ? 'true' : 'false'
 | 
						|
      case 'undefined':
 | 
						|
        return undefined
 | 
						|
      case 'bigint':
 | 
						|
        if (bigint) {
 | 
						|
          return String(value)
 | 
						|
        }
 | 
						|
        // fallthrough
 | 
						|
      default:
 | 
						|
        return fail ? fail(value) : undefined
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function stringify (value, replacer, space) {
 | 
						|
    if (arguments.length > 1) {
 | 
						|
      let spacer = ''
 | 
						|
      if (typeof space === 'number') {
 | 
						|
        spacer = ' '.repeat(Math.min(space, 10))
 | 
						|
      } else if (typeof space === 'string') {
 | 
						|
        spacer = space.slice(0, 10)
 | 
						|
      }
 | 
						|
      if (replacer != null) {
 | 
						|
        if (typeof replacer === 'function') {
 | 
						|
          return stringifyFnReplacer('', { '': value }, [], replacer, spacer, '')
 | 
						|
        }
 | 
						|
        if (Array.isArray(replacer)) {
 | 
						|
          return stringifyArrayReplacer('', value, [], getUniqueReplacerSet(replacer), spacer, '')
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (spacer.length !== 0) {
 | 
						|
        return stringifyIndent('', value, [], spacer, '')
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return stringifySimple('', value, [])
 | 
						|
  }
 | 
						|
 | 
						|
  return stringify
 | 
						|
}
 |