CoolFace
Apppublic

strong-tie/inbound-calls

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
1'use strict'2 3const { hasOwnProperty } = Object.prototype4 5const stringify = configure()6 7// @ts-expect-error8stringify.configure = configure9// @ts-expect-error10stringify.stringify = stringify11 12// @ts-expect-error13stringify.default = stringify14 15// @ts-expect-error used for named export16exports.stringify = stringify17// @ts-expect-error used for named export18exports.configure = configure19 20module.exports = stringify21 22// eslint-disable-next-line no-control-regex23const strEscapeSequencesRegExp = /[\u0000-\u001f\u0022\u005c\ud800-\udfff]/24 25// Escape C0 control characters, double quotes, the backslash and every code26// unit with a numeric value in the inclusive range 0xD800 to 0xDFFF.27function strEscape (str) {28  // Some magic numbers that worked out fine while benchmarking with v8 8.029  if (str.length < 5000 && !strEscapeSequencesRegExp.test(str)) {30    return `"${str}"`31  }32  return JSON.stringify(str)33}34 35function sort (array, comparator) {36  // Insertion sort is very efficient for small input sizes, but it has a bad37  // worst case complexity. Thus, use native array sort for bigger values.38  if (array.length > 2e2 || comparator) {39    return array.sort(comparator)40  }41  for (let i = 1; i < array.length; i++) {42    const currentValue = array[i]43    let position = i44    while (position !== 0 && array[position - 1] > currentValue) {45      array[position] = array[position - 1]46      position--47    }48    array[position] = currentValue49  }50  return array51}52 53const typedArrayPrototypeGetSymbolToStringTag =54  Object.getOwnPropertyDescriptor(55    Object.getPrototypeOf(56      Object.getPrototypeOf(57        new Int8Array()58      )59    ),60    Symbol.toStringTag61  ).get62 63function isTypedArrayWithEntries (value) {64  return typedArrayPrototypeGetSymbolToStringTag.call(value) !== undefined && value.length !== 065}66 67function stringifyTypedArray (array, separator, maximumBreadth) {68  if (array.length < maximumBreadth) {69    maximumBreadth = array.length70  }71  const whitespace = separator === ',' ? '' : ' '72  let res = `"0":${whitespace}${array[0]}`73  for (let i = 1; i < maximumBreadth; i++) {74    res += `${separator}"${i}":${whitespace}${array[i]}`75  }76  return res77}78 79function getCircularValueOption (options) {80  if (hasOwnProperty.call(options, 'circularValue')) {81    const circularValue = options.circularValue82    if (typeof circularValue === 'string') {83      return `"${circularValue}"`84    }85    if (circularValue == null) {86      return circularValue87    }88    if (circularValue === Error || circularValue === TypeError) {89      return {90        toString () {91          throw new TypeError('Converting circular structure to JSON')92        }93      }94    }95    throw new TypeError('The "circularValue" argument must be of type string or the value null or undefined')96  }97  return '"[Circular]"'98}99 100function getDeterministicOption (options) {101  let value102  if (hasOwnProperty.call(options, 'deterministic')) {103    value = options.deterministic104    if (typeof value !== 'boolean' && typeof value !== 'function') {105      throw new TypeError('The "deterministic" argument must be of type boolean or comparator function')106    }107  }108  return value === undefined ? true : value109}110 111function getBooleanOption (options, key) {112  let value113  if (hasOwnProperty.call(options, key)) {114    value = options[key]115    if (typeof value !== 'boolean') {116      throw new TypeError(`The "${key}" argument must be of type boolean`)117    }118  }119  return value === undefined ? true : value120}121 122function getPositiveIntegerOption (options, key) {123  let value124  if (hasOwnProperty.call(options, key)) {125    value = options[key]126    if (typeof value !== 'number') {127      throw new TypeError(`The "${key}" argument must be of type number`)128    }129    if (!Number.isInteger(value)) {130      throw new TypeError(`The "${key}" argument must be an integer`)131    }132    if (value < 1) {133      throw new RangeError(`The "${key}" argument must be >= 1`)134    }135  }136  return value === undefined ? Infinity : value137}138 139function getItemCount (number) {140  if (number === 1) {141    return '1 item'142  }143  return `${number} items`144}145 146function getUniqueReplacerSet (replacerArray) {147  const replacerSet = new Set()148  for (const value of replacerArray) {149    if (typeof value === 'string' || typeof value === 'number') {150      replacerSet.add(String(value))151    }152  }153  return replacerSet154}155 156function getStrictOption (options) {157  if (hasOwnProperty.call(options, 'strict')) {158    const value = options.strict159    if (typeof value !== 'boolean') {160      throw new TypeError('The "strict" argument must be of type boolean')161    }162    if (value) {163      return (value) => {164        let message = `Object can not safely be stringified. Received type ${typeof value}`165        if (typeof value !== 'function') message += ` (${value.toString()})`166        throw new Error(message)167      }168    }169  }170}171 172function configure (options) {173  options = { ...options }174  const fail = getStrictOption(options)175  if (fail) {176    if (options.bigint === undefined) {177      options.bigint = false178    }179    if (!('circularValue' in options)) {180      options.circularValue = Error181    }182  }183  const circularValue = getCircularValueOption(options)184  const bigint = getBooleanOption(options, 'bigint')185  const deterministic = getDeterministicOption(options)186  const comparator = typeof deterministic === 'function' ? deterministic : undefined187  const maximumDepth = getPositiveIntegerOption(options, 'maximumDepth')188  const maximumBreadth = getPositiveIntegerOption(options, 'maximumBreadth')189 190  function stringifyFnReplacer (key, parent, stack, replacer, spacer, indentation) {191    let value = parent[key]192 193    if (typeof value === 'object' && value !== null && typeof value.toJSON === 'function') {194      value = value.toJSON(key)195    }196    value = replacer.call(parent, key, value)197 198    switch (typeof value) {199      case 'string':200        return strEscape(value)201      case 'object': {202        if (value === null) {203          return 'null'204        }205        if (stack.indexOf(value) !== -1) {206          return circularValue207        }208 209        let res = ''210        let join = ','211        const originalIndentation = indentation212 213        if (Array.isArray(value)) {214          if (value.length === 0) {215            return '[]'216          }217          if (maximumDepth < stack.length + 1) {218            return '"[Array]"'219          }220          stack.push(value)221          if (spacer !== '') {222            indentation += spacer223            res += `\n${indentation}`224            join = `,\n${indentation}`225          }226          const maximumValuesToStringify = Math.min(value.length, maximumBreadth)227          let i = 0228          for (; i < maximumValuesToStringify - 1; i++) {229            const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation)230            res += tmp !== undefined ? tmp : 'null'231            res += join232          }233          const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation)234          res += tmp !== undefined ? tmp : 'null'235          if (value.length - 1 > maximumBreadth) {236            const removedKeys = value.length - maximumBreadth - 1237            res += `${join}"... ${getItemCount(removedKeys)} not stringified"`238          }239          if (spacer !== '') {240            res += `\n${originalIndentation}`241          }242          stack.pop()243          return `[${res}]`244        }245 246        let keys = Object.keys(value)247        const keyLength = keys.length248        if (keyLength === 0) {249          return '{}'250        }251        if (maximumDepth < stack.length + 1) {252          return '"[Object]"'253        }254        let whitespace = ''255        let separator = ''256        if (spacer !== '') {257          indentation += spacer258          join = `,\n${indentation}`259          whitespace = ' '260        }261        const maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth)262        if (deterministic && !isTypedArrayWithEntries(value)) {263          keys = sort(keys, comparator)264        }265        stack.push(value)266        for (let i = 0; i < maximumPropertiesToStringify; i++) {267          const key = keys[i]268          const tmp = stringifyFnReplacer(key, value, stack, replacer, spacer, indentation)269          if (tmp !== undefined) {270            res += `${separator}${strEscape(key)}:${whitespace}${tmp}`271            separator = join272          }273        }274        if (keyLength > maximumBreadth) {275          const removedKeys = keyLength - maximumBreadth276          res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`277          separator = join278        }279        if (spacer !== '' && separator.length > 1) {280          res = `\n${indentation}${res}\n${originalIndentation}`281        }282        stack.pop()283        return `{${res}}`284      }285      case 'number':286        return isFinite(value) ? String(value) : fail ? fail(value) : 'null'287      case 'boolean':288        return value === true ? 'true' : 'false'289      case 'undefined':290        return undefined291      case 'bigint':292        if (bigint) {293          return String(value)294        }295        // fallthrough296      default:297        return fail ? fail(value) : undefined298    }299  }300 301  function stringifyArrayReplacer (key, value, stack, replacer, spacer, indentation) {302    if (typeof value === 'object' && value !== null && typeof value.toJSON === 'function') {303      value = value.toJSON(key)304    }305 306    switch (typeof value) {307      case 'string':308        return strEscape(value)309      case 'object': {310        if (value === null) {311          return 'null'312        }313        if (stack.indexOf(value) !== -1) {314          return circularValue315        }316 317        const originalIndentation = indentation318        let res = ''319        let join = ','320 321        if (Array.isArray(value)) {322          if (value.length === 0) {323            return '[]'324          }325          if (maximumDepth < stack.length + 1) {326            return '"[Array]"'327          }328          stack.push(value)329          if (spacer !== '') {330            indentation += spacer331            res += `\n${indentation}`332            join = `,\n${indentation}`333          }334          const maximumValuesToStringify = Math.min(value.length, maximumBreadth)335          let i = 0336          for (; i < maximumValuesToStringify - 1; i++) {337            const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation)338            res += tmp !== undefined ? tmp : 'null'339            res += join340          }341          const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation)342          res += tmp !== undefined ? tmp : 'null'343          if (value.length - 1 > maximumBreadth) {344            const removedKeys = value.length - maximumBreadth - 1345            res += `${join}"... ${getItemCount(removedKeys)} not stringified"`346          }347          if (spacer !== '') {348            res += `\n${originalIndentation}`349          }350          stack.pop()351          return `[${res}]`352        }353        stack.push(value)354        let whitespace = ''355        if (spacer !== '') {356          indentation += spacer357          join = `,\n${indentation}`358          whitespace = ' '359        }360        let separator = ''361        for (const key of replacer) {362          const tmp = stringifyArrayReplacer(key, value[key], stack, replacer, spacer, indentation)363          if (tmp !== undefined) {364            res += `${separator}${strEscape(key)}:${whitespace}${tmp}`365            separator = join366          }367        }368        if (spacer !== '' && separator.length > 1) {369          res = `\n${indentation}${res}\n${originalIndentation}`370        }371        stack.pop()372        return `{${res}}`373      }374      case 'number':375        return isFinite(value) ? String(value) : fail ? fail(value) : 'null'376      case 'boolean':377        return value === true ? 'true' : 'false'378      case 'undefined':379        return undefined380      case 'bigint':381        if (bigint) {382          return String(value)383        }384        // fallthrough385      default:386        return fail ? fail(value) : undefined387    }388  }389 390  function stringifyIndent (key, value, stack, spacer, indentation) {391    switch (typeof value) {392      case 'string':393        return strEscape(value)394      case 'object': {395        if (value === null) {396          return 'null'397        }398        if (typeof value.toJSON === 'function') {399          value = value.toJSON(key)400          // Prevent calling `toJSON` again.401          if (typeof value !== 'object') {402            return stringifyIndent(key, value, stack, spacer, indentation)403          }404          if (value === null) {405            return 'null'406          }407        }408        if (stack.indexOf(value) !== -1) {409          return circularValue410        }411        const originalIndentation = indentation412 413        if (Array.isArray(value)) {414          if (value.length === 0) {415            return '[]'416          }417          if (maximumDepth < stack.length + 1) {418            return '"[Array]"'419          }420          stack.push(value)421          indentation += spacer422          let res = `\n${indentation}`423          const join = `,\n${indentation}`424          const maximumValuesToStringify = Math.min(value.length, maximumBreadth)425          let i = 0426          for (; i < maximumValuesToStringify - 1; i++) {427            const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation)428            res += tmp !== undefined ? tmp : 'null'429            res += join430          }431          const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation)432          res += tmp !== undefined ? tmp : 'null'433          if (value.length - 1 > maximumBreadth) {434            const removedKeys = value.length - maximumBreadth - 1435            res += `${join}"... ${getItemCount(removedKeys)} not stringified"`436          }437          res += `\n${originalIndentation}`438          stack.pop()439          return `[${res}]`440        }441 442        let keys = Object.keys(value)443        const keyLength = keys.length444        if (keyLength === 0) {445          return '{}'446        }447        if (maximumDepth < stack.length + 1) {448          return '"[Object]"'449        }450        indentation += spacer451        const join = `,\n${indentation}`452        let res = ''453        let separator = ''454        let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth)455        if (isTypedArrayWithEntries(value)) {456          res += stringifyTypedArray(value, join, maximumBreadth)457          keys = keys.slice(value.length)458          maximumPropertiesToStringify -= value.length459          separator = join460        }461        if (deterministic) {462          keys = sort(keys, comparator)463        }464        stack.push(value)465        for (let i = 0; i < maximumPropertiesToStringify; i++) {466          const key = keys[i]467          const tmp = stringifyIndent(key, value[key], stack, spacer, indentation)468          if (tmp !== undefined) {469            res += `${separator}${strEscape(key)}: ${tmp}`470            separator = join471          }472        }473        if (keyLength > maximumBreadth) {474          const removedKeys = keyLength - maximumBreadth475          res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`476          separator = join477        }478        if (separator !== '') {479          res = `\n${indentation}${res}\n${originalIndentation}`480        }481        stack.pop()482        return `{${res}}`483      }484      case 'number':485        return isFinite(value) ? String(value) : fail ? fail(value) : 'null'486      case 'boolean':487        return value === true ? 'true' : 'false'488      case 'undefined':489        return undefined490      case 'bigint':491        if (bigint) {492          return String(value)493        }494        // fallthrough495      default:496        return fail ? fail(value) : undefined497    }498  }499 500  function stringifySimple (key, value, stack) {501    switch (typeof value) {502      case 'string':503        return strEscape(value)504      case 'object': {505        if (value === null) {506          return 'null'507        }508        if (typeof value.toJSON === 'function') {509          value = value.toJSON(key)510          // Prevent calling `toJSON` again511          if (typeof value !== 'object') {512            return stringifySimple(key, value, stack)513          }514          if (value === null) {515            return 'null'516          }517        }518        if (stack.indexOf(value) !== -1) {519          return circularValue520        }521 522        let res = ''523 524        const hasLength = value.length !== undefined525        if (hasLength && Array.isArray(value)) {526          if (value.length === 0) {527            return '[]'528          }529          if (maximumDepth < stack.length + 1) {530            return '"[Array]"'531          }532          stack.push(value)533          const maximumValuesToStringify = Math.min(value.length, maximumBreadth)534          let i = 0535          for (; i < maximumValuesToStringify - 1; i++) {536            const tmp = stringifySimple(String(i), value[i], stack)537            res += tmp !== undefined ? tmp : 'null'538            res += ','539          }540          const tmp = stringifySimple(String(i), value[i], stack)541          res += tmp !== undefined ? tmp : 'null'542          if (value.length - 1 > maximumBreadth) {543            const removedKeys = value.length - maximumBreadth - 1544            res += `,"... ${getItemCount(removedKeys)} not stringified"`545          }546          stack.pop()547          return `[${res}]`548        }549 550        let keys = Object.keys(value)551        const keyLength = keys.length552        if (keyLength === 0) {553          return '{}'554        }555        if (maximumDepth < stack.length + 1) {556          return '"[Object]"'557        }558        let separator = ''559        let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth)560        if (hasLength && isTypedArrayWithEntries(value)) {561          res += stringifyTypedArray(value, ',', maximumBreadth)562          keys = keys.slice(value.length)563          maximumPropertiesToStringify -= value.length564          separator = ','565        }566        if (deterministic) {567          keys = sort(keys, comparator)568        }569        stack.push(value)570        for (let i = 0; i < maximumPropertiesToStringify; i++) {571          const key = keys[i]572          const tmp = stringifySimple(key, value[key], stack)573          if (tmp !== undefined) {574            res += `${separator}${strEscape(key)}:${tmp}`575            separator = ','576          }577        }578        if (keyLength > maximumBreadth) {579          const removedKeys = keyLength - maximumBreadth580          res += `${separator}"...":"${getItemCount(removedKeys)} not stringified"`581        }582        stack.pop()583        return `{${res}}`584      }585      case 'number':586        return isFinite(value) ? String(value) : fail ? fail(value) : 'null'587      case 'boolean':588        return value === true ? 'true' : 'false'589      case 'undefined':590        return undefined591      case 'bigint':592        if (bigint) {593          return String(value)594        }595        // fallthrough596      default:597        return fail ? fail(value) : undefined598    }599  }600 601  function stringify (value, replacer, space) {602    if (arguments.length > 1) {603      let spacer = ''604      if (typeof space === 'number') {605        spacer = ' '.repeat(Math.min(space, 10))606      } else if (typeof space === 'string') {607        spacer = space.slice(0, 10)608      }609      if (replacer != null) {610        if (typeof replacer === 'function') {611          return stringifyFnReplacer('', { '': value }, [], replacer, spacer, '')612        }613        if (Array.isArray(replacer)) {614          return stringifyArrayReplacer('', value, [], getUniqueReplacerSet(replacer), spacer, '')615        }616      }617      if (spacer.length !== 0) {618        return stringifyIndent('', value, [], spacer, '')619      }620    }621    return stringifySimple('', value, [])622  }623 624  return stringify625}626