123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- module.exports = stringify
- stringify.default = stringify
- stringify.stable = deterministicStringify
- stringify.stableStringify = deterministicStringify
- var arr = []
- var replacerStack = []
- // Regular stringify
- function stringify (obj, replacer, spacer) {
- decirc(obj, '', [], undefined)
- var res
- if (replacerStack.length === 0) {
- res = JSON.stringify(obj, replacer, spacer)
- } else {
- res = JSON.stringify(obj, replaceGetterValues(replacer), spacer)
- }
- while (arr.length !== 0) {
- var part = arr.pop()
- if (part.length === 4) {
- Object.defineProperty(part[0], part[1], part[3])
- } else {
- part[0][part[1]] = part[2]
- }
- }
- return res
- }
- function decirc (val, k, stack, parent) {
- var i
- if (typeof val === 'object' && val !== null) {
- for (i = 0; i < stack.length; i++) {
- if (stack[i] === val) {
- var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k)
- if (propertyDescriptor.get !== undefined) {
- if (propertyDescriptor.configurable) {
- Object.defineProperty(parent, k, { value: '[Circular]' })
- arr.push([parent, k, val, propertyDescriptor])
- } else {
- replacerStack.push([val, k])
- }
- } else {
- parent[k] = '[Circular]'
- arr.push([parent, k, val])
- }
- return
- }
- }
- stack.push(val)
- // Optimize for Arrays. Big arrays could kill the performance otherwise!
- if (Array.isArray(val)) {
- for (i = 0; i < val.length; i++) {
- decirc(val[i], i, stack, val)
- }
- } else {
- var keys = Object.keys(val)
- for (i = 0; i < keys.length; i++) {
- var key = keys[i]
- decirc(val[key], key, stack, val)
- }
- }
- stack.pop()
- }
- }
- // Stable-stringify
- function compareFunction (a, b) {
- if (a < b) {
- return -1
- }
- if (a > b) {
- return 1
- }
- return 0
- }
- function deterministicStringify (obj, replacer, spacer) {
- var tmp = deterministicDecirc(obj, '', [], undefined) || obj
- var res
- if (replacerStack.length === 0) {
- res = JSON.stringify(tmp, replacer, spacer)
- } else {
- res = JSON.stringify(tmp, replaceGetterValues(replacer), spacer)
- }
- while (arr.length !== 0) {
- var part = arr.pop()
- if (part.length === 4) {
- Object.defineProperty(part[0], part[1], part[3])
- } else {
- part[0][part[1]] = part[2]
- }
- }
- return res
- }
- function deterministicDecirc (val, k, stack, parent) {
- var i
- if (typeof val === 'object' && val !== null) {
- for (i = 0; i < stack.length; i++) {
- if (stack[i] === val) {
- var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k)
- if (propertyDescriptor.get !== undefined) {
- if (propertyDescriptor.configurable) {
- Object.defineProperty(parent, k, { value: '[Circular]' })
- arr.push([parent, k, val, propertyDescriptor])
- } else {
- replacerStack.push([val, k])
- }
- } else {
- parent[k] = '[Circular]'
- arr.push([parent, k, val])
- }
- return
- }
- }
- if (typeof val.toJSON === 'function') {
- return
- }
- stack.push(val)
- // Optimize for Arrays. Big arrays could kill the performance otherwise!
- if (Array.isArray(val)) {
- for (i = 0; i < val.length; i++) {
- deterministicDecirc(val[i], i, stack, val)
- }
- } else {
- // Create a temporary object in the required way
- var tmp = {}
- var keys = Object.keys(val).sort(compareFunction)
- for (i = 0; i < keys.length; i++) {
- var key = keys[i]
- deterministicDecirc(val[key], key, stack, val)
- tmp[key] = val[key]
- }
- if (parent !== undefined) {
- arr.push([parent, k, val])
- parent[k] = tmp
- } else {
- return tmp
- }
- }
- stack.pop()
- }
- }
- // wraps replacer function to handle values we couldn't replace
- // and mark them as [Circular]
- function replaceGetterValues (replacer) {
- replacer = replacer !== undefined ? replacer : function (k, v) { return v }
- return function (key, val) {
- if (replacerStack.length > 0) {
- for (var i = 0; i < replacerStack.length; i++) {
- var part = replacerStack[i]
- if (part[1] === key && part[0] === val) {
- val = '[Circular]'
- replacerStack.splice(i, 1)
- break
- }
- }
- }
- return replacer.call(this, key, val)
- }
- }
|