You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					230 lines
				
				5.7 KiB
			
		
		
			
		
	
	
					230 lines
				
				5.7 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								module.exports = stringify
							 | 
						||
| 
								 | 
							
								stringify.default = stringify
							 | 
						||
| 
								 | 
							
								stringify.stable = deterministicStringify
							 | 
						||
| 
								 | 
							
								stringify.stableStringify = deterministicStringify
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var LIMIT_REPLACE_NODE = '[...]'
							 | 
						||
| 
								 | 
							
								var CIRCULAR_REPLACE_NODE = '[Circular]'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var arr = []
							 | 
						||
| 
								 | 
							
								var replacerStack = []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function defaultOptions () {
							 | 
						||
| 
								 | 
							
								  return {
							 | 
						||
| 
								 | 
							
								    depthLimit: Number.MAX_SAFE_INTEGER,
							 | 
						||
| 
								 | 
							
								    edgesLimit: Number.MAX_SAFE_INTEGER
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Regular stringify
							 | 
						||
| 
								 | 
							
								function stringify (obj, replacer, spacer, options) {
							 | 
						||
| 
								 | 
							
								  if (typeof options === 'undefined') {
							 | 
						||
| 
								 | 
							
								    options = defaultOptions()
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  decirc(obj, '', 0, [], undefined, 0, options)
							 | 
						||
| 
								 | 
							
								  var res
							 | 
						||
| 
								 | 
							
								  try {
							 | 
						||
| 
								 | 
							
								    if (replacerStack.length === 0) {
							 | 
						||
| 
								 | 
							
								      res = JSON.stringify(obj, replacer, spacer)
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      res = JSON.stringify(obj, replaceGetterValues(replacer), spacer)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  } catch (_) {
							 | 
						||
| 
								 | 
							
								    return JSON.stringify('[unable to serialize, circular reference is too complex to analyze]')
							 | 
						||
| 
								 | 
							
								  } finally {
							 | 
						||
| 
								 | 
							
								    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 setReplace (replace, val, k, parent) {
							 | 
						||
| 
								 | 
							
								  var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k)
							 | 
						||
| 
								 | 
							
								  if (propertyDescriptor.get !== undefined) {
							 | 
						||
| 
								 | 
							
								    if (propertyDescriptor.configurable) {
							 | 
						||
| 
								 | 
							
								      Object.defineProperty(parent, k, { value: replace })
							 | 
						||
| 
								 | 
							
								      arr.push([parent, k, val, propertyDescriptor])
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      replacerStack.push([val, k, replace])
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    parent[k] = replace
							 | 
						||
| 
								 | 
							
								    arr.push([parent, k, val])
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function decirc (val, k, edgeIndex, stack, parent, depth, options) {
							 | 
						||
| 
								 | 
							
								  depth += 1
							 | 
						||
| 
								 | 
							
								  var i
							 | 
						||
| 
								 | 
							
								  if (typeof val === 'object' && val !== null) {
							 | 
						||
| 
								 | 
							
								    for (i = 0; i < stack.length; i++) {
							 | 
						||
| 
								 | 
							
								      if (stack[i] === val) {
							 | 
						||
| 
								 | 
							
								        setReplace(CIRCULAR_REPLACE_NODE, val, k, parent)
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (
							 | 
						||
| 
								 | 
							
								      typeof options.depthLimit !== 'undefined' &&
							 | 
						||
| 
								 | 
							
								      depth > options.depthLimit
							 | 
						||
| 
								 | 
							
								    ) {
							 | 
						||
| 
								 | 
							
								      setReplace(LIMIT_REPLACE_NODE, val, k, parent)
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (
							 | 
						||
| 
								 | 
							
								      typeof options.edgesLimit !== 'undefined' &&
							 | 
						||
| 
								 | 
							
								      edgeIndex + 1 > options.edgesLimit
							 | 
						||
| 
								 | 
							
								    ) {
							 | 
						||
| 
								 | 
							
								      setReplace(LIMIT_REPLACE_NODE, val, k, parent)
							 | 
						||
| 
								 | 
							
								      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, i, stack, val, depth, options)
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      var keys = Object.keys(val)
							 | 
						||
| 
								 | 
							
								      for (i = 0; i < keys.length; i++) {
							 | 
						||
| 
								 | 
							
								        var key = keys[i]
							 | 
						||
| 
								 | 
							
								        decirc(val[key], key, i, stack, val, depth, options)
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    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, options) {
							 | 
						||
| 
								 | 
							
								  if (typeof options === 'undefined') {
							 | 
						||
| 
								 | 
							
								    options = defaultOptions()
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var tmp = deterministicDecirc(obj, '', 0, [], undefined, 0, options) || obj
							 | 
						||
| 
								 | 
							
								  var res
							 | 
						||
| 
								 | 
							
								  try {
							 | 
						||
| 
								 | 
							
								    if (replacerStack.length === 0) {
							 | 
						||
| 
								 | 
							
								      res = JSON.stringify(tmp, replacer, spacer)
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      res = JSON.stringify(tmp, replaceGetterValues(replacer), spacer)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  } catch (_) {
							 | 
						||
| 
								 | 
							
								    return JSON.stringify('[unable to serialize, circular reference is too complex to analyze]')
							 | 
						||
| 
								 | 
							
								  } finally {
							 | 
						||
| 
								 | 
							
								    // Ensure that we restore the object as it was.
							 | 
						||
| 
								 | 
							
								    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, edgeIndex, stack, parent, depth, options) {
							 | 
						||
| 
								 | 
							
								  depth += 1
							 | 
						||
| 
								 | 
							
								  var i
							 | 
						||
| 
								 | 
							
								  if (typeof val === 'object' && val !== null) {
							 | 
						||
| 
								 | 
							
								    for (i = 0; i < stack.length; i++) {
							 | 
						||
| 
								 | 
							
								      if (stack[i] === val) {
							 | 
						||
| 
								 | 
							
								        setReplace(CIRCULAR_REPLACE_NODE, val, k, parent)
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								      if (typeof val.toJSON === 'function') {
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    } catch (_) {
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (
							 | 
						||
| 
								 | 
							
								      typeof options.depthLimit !== 'undefined' &&
							 | 
						||
| 
								 | 
							
								      depth > options.depthLimit
							 | 
						||
| 
								 | 
							
								    ) {
							 | 
						||
| 
								 | 
							
								      setReplace(LIMIT_REPLACE_NODE, val, k, parent)
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (
							 | 
						||
| 
								 | 
							
								      typeof options.edgesLimit !== 'undefined' &&
							 | 
						||
| 
								 | 
							
								      edgeIndex + 1 > options.edgesLimit
							 | 
						||
| 
								 | 
							
								    ) {
							 | 
						||
| 
								 | 
							
								      setReplace(LIMIT_REPLACE_NODE, val, k, parent)
							 | 
						||
| 
								 | 
							
								      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, i, stack, val, depth, options)
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    } 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, i, stack, val, depth, options)
							 | 
						||
| 
								 | 
							
								        tmp[key] = val[key]
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (typeof 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 replaced value
							 | 
						||
| 
								 | 
							
								function replaceGetterValues (replacer) {
							 | 
						||
| 
								 | 
							
								  replacer =
							 | 
						||
| 
								 | 
							
								    typeof 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 = part[2]
							 | 
						||
| 
								 | 
							
								          replacerStack.splice(i, 1)
							 | 
						||
| 
								 | 
							
								          break
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return replacer.call(this, key, val)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 |