function parseString (str) {
  if (str === '') {
    return ''
  }

  const lower = str.toLowerCase()
  if (lower === 'null') {
    return null
  }
  if (lower === 'true') {
    return true
  }
  if (lower === 'false') {
    return false
  }

  const containsLeadingZero = /^0\d+$/
  const startsWithZeroPrefix = /^0[xbo]/i // hex, binary, octal numbers
  if (containsLeadingZero.test(str) || startsWithZeroPrefix.test(str)) {
    // treat '001', '0x1A', '0b1101', and '0o3700' as a string
    return str
  }

  const num = Number(str) // will nicely fail with '123ab'
  const numFloat = parseFloat(str) // will nicely fail with '  '
  const isFiniteNumber = !isNaN(num) && !isNaN(numFloat) && isFinite(num)
  const isInSafeRange = num <= Number.MAX_SAFE_INTEGER && num >= Number.MIN_SAFE_INTEGER
  const isInteger = /^\d+$/.test(str)
  if (isFiniteNumber && (isInSafeRange || !isInteger)) {
    return num
  }

  return str
}
Cast contents of a string to the correct type.
This can be a string, a number, a boolean, etc
@param {String} str
@return {*} castedStr
@private