index.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. module.exports = stringify
  2. stringify.default = stringify
  3. stringify.stable = deterministicStringify
  4. stringify.stableStringify = deterministicStringify
  5. var arr = []
  6. // Regular stringify
  7. function stringify (obj, replacer, spacer) {
  8. decirc(obj, '', [], undefined)
  9. var res = JSON.stringify(obj, replacer, spacer)
  10. while (arr.length !== 0) {
  11. var part = arr.pop()
  12. part[0][part[1]] = part[2]
  13. }
  14. return res
  15. }
  16. function decirc (val, k, stack, parent) {
  17. var i
  18. if (typeof val === 'object' && val !== null) {
  19. for (i = 0; i < stack.length; i++) {
  20. if (stack[i] === val) {
  21. parent[k] = '[Circular]'
  22. arr.push([parent, k, val])
  23. return
  24. }
  25. }
  26. stack.push(val)
  27. // Optimize for Arrays. Big arrays could kill the performance otherwise!
  28. if (Array.isArray(val)) {
  29. for (i = 0; i < val.length; i++) {
  30. decirc(val[i], i, stack, val)
  31. }
  32. } else {
  33. var keys = Object.keys(val)
  34. for (i = 0; i < keys.length; i++) {
  35. var key = keys[i]
  36. decirc(val[key], key, stack, val)
  37. }
  38. }
  39. stack.pop()
  40. }
  41. }
  42. // Stable-stringify
  43. function compareFunction (a, b) {
  44. if (a < b) {
  45. return -1
  46. }
  47. if (a > b) {
  48. return 1
  49. }
  50. return 0
  51. }
  52. function deterministicStringify (obj, replacer, spacer) {
  53. var tmp = deterministicDecirc(obj, '', [], undefined) || obj
  54. var res = JSON.stringify(tmp, replacer, spacer)
  55. while (arr.length !== 0) {
  56. var part = arr.pop()
  57. part[0][part[1]] = part[2]
  58. }
  59. return res
  60. }
  61. function deterministicDecirc (val, k, stack, parent) {
  62. var i
  63. if (typeof val === 'object' && val !== null) {
  64. for (i = 0; i < stack.length; i++) {
  65. if (stack[i] === val) {
  66. parent[k] = '[Circular]'
  67. arr.push([parent, k, val])
  68. return
  69. }
  70. }
  71. if (typeof val.toJSON === 'function') {
  72. return
  73. }
  74. stack.push(val)
  75. // Optimize for Arrays. Big arrays could kill the performance otherwise!
  76. if (Array.isArray(val)) {
  77. for (i = 0; i < val.length; i++) {
  78. deterministicDecirc(val[i], i, stack, val)
  79. }
  80. } else {
  81. // Create a temporary object in the required way
  82. var tmp = {}
  83. var keys = Object.keys(val).sort(compareFunction)
  84. for (i = 0; i < keys.length; i++) {
  85. var key = keys[i]
  86. deterministicDecirc(val[key], key, stack, val)
  87. tmp[key] = val[key]
  88. }
  89. if (parent !== undefined) {
  90. arr.push([parent, k, val])
  91. parent[k] = tmp
  92. } else {
  93. return tmp
  94. }
  95. }
  96. stack.pop()
  97. }
  98. }