mirror of
				https://github.com/1disk/edp445.git
				synced 2024-08-14 22:47:02 +00:00 
			
		
		
		
	Changed alot of things.
This commit is contained in:
		
							parent
							
								
									a5a0523e5a
								
							
						
					
					
						commit
						3513d5390c
					
				
					 2016 changed files with 336930 additions and 9 deletions
				
			
		
							
								
								
									
										8
									
								
								node_modules/fast-safe-stringify/.travis.yml
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								node_modules/fast-safe-stringify/.travis.yml
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| language: node_js | ||||
| sudo: false | ||||
| node_js: | ||||
| - '4' | ||||
| - '6' | ||||
| - '8' | ||||
| - '9' | ||||
| - '10' | ||||
							
								
								
									
										17
									
								
								node_modules/fast-safe-stringify/CHANGELOG.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								node_modules/fast-safe-stringify/CHANGELOG.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| # Changelog | ||||
| 
 | ||||
| ## v.2.0.0 | ||||
| 
 | ||||
| Features | ||||
| 
 | ||||
| - Added stable-stringify (see documentation) | ||||
| - Support replacer | ||||
| - Support spacer | ||||
| - toJSON support without forceDecirc property | ||||
| - Improved performance | ||||
| 
 | ||||
| Breaking changes | ||||
| 
 | ||||
| - Manipulating the input value in a `toJSON` function is not possible anymore in | ||||
|   all cases (see documentation) | ||||
| - Dropped support for e.g. IE8 and Node.js < 4 | ||||
							
								
								
									
										23
									
								
								node_modules/fast-safe-stringify/LICENSE
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								node_modules/fast-safe-stringify/LICENSE
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2016 David Mark Clements | ||||
| Copyright (c) 2017 David Mark Clements & Matteo Collina | ||||
| Copyright (c) 2018 David Mark Clements, Matteo Collina & Ruben Bridgewater  | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										137
									
								
								node_modules/fast-safe-stringify/benchmark.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								node_modules/fast-safe-stringify/benchmark.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,137 @@ | |||
| const Benchmark = require('benchmark') | ||||
| const suite = new Benchmark.Suite() | ||||
| const { inspect } = require('util') | ||||
| const jsonStringifySafe = require('json-stringify-safe') | ||||
| const fastSafeStringify = require('./') | ||||
| 
 | ||||
| const array = new Array(10).fill(0).map((_, i) => i) | ||||
| const obj = { foo: array } | ||||
| const circ = JSON.parse(JSON.stringify(obj)) | ||||
| circ.o = { obj: circ, array } | ||||
| const circGetters = JSON.parse(JSON.stringify(obj)) | ||||
| Object.assign(circGetters, { get o () { return { obj: circGetters, array } } }) | ||||
| 
 | ||||
| const deep = require('./package.json') | ||||
| deep.deep = JSON.parse(JSON.stringify(deep)) | ||||
| deep.deep.deep = JSON.parse(JSON.stringify(deep)) | ||||
| deep.deep.deep.deep = JSON.parse(JSON.stringify(deep)) | ||||
| deep.array = array | ||||
| 
 | ||||
| const deepCirc = JSON.parse(JSON.stringify(deep)) | ||||
| deepCirc.deep.deep.deep.circ = deepCirc | ||||
| deepCirc.deep.deep.circ = deepCirc | ||||
| deepCirc.deep.circ = deepCirc | ||||
| deepCirc.array = array | ||||
| 
 | ||||
| const deepCircGetters = JSON.parse(JSON.stringify(deep)) | ||||
| for (let i = 0; i < 10; i++) { | ||||
|   deepCircGetters[i.toString()] = { | ||||
|     deep: { | ||||
|       deep: { | ||||
|         get circ () { return deep.deep }, | ||||
|         deep: { get circ () { return deep.deep.deep } } | ||||
|       }, | ||||
|       get circ () { return deep } | ||||
|     }, | ||||
|     get array () { return array } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const deepCircNonCongifurableGetters = JSON.parse(JSON.stringify(deep)) | ||||
| Object.defineProperty(deepCircNonCongifurableGetters.deep.deep.deep, 'circ', { | ||||
|   get: () => deepCircNonCongifurableGetters, | ||||
|   enumerable: true, | ||||
|   configurable: false | ||||
| }) | ||||
| Object.defineProperty(deepCircNonCongifurableGetters.deep.deep, 'circ', { | ||||
|   get: () => deepCircNonCongifurableGetters, | ||||
|   enumerable: true, | ||||
|   configurable: false | ||||
| }) | ||||
| Object.defineProperty(deepCircNonCongifurableGetters.deep, 'circ', { | ||||
|   get: () => deepCircNonCongifurableGetters, | ||||
|   enumerable: true, | ||||
|   configurable: false | ||||
| }) | ||||
| Object.defineProperty(deepCircNonCongifurableGetters, 'array', { | ||||
|   get: () => array, | ||||
|   enumerable: true, | ||||
|   configurable: false | ||||
| }) | ||||
| 
 | ||||
| suite.add('util.inspect:          simple object                 ', function () { | ||||
|   inspect(obj, { showHidden: false, depth: null }) | ||||
| }) | ||||
| suite.add('util.inspect:          circular                      ', function () { | ||||
|   inspect(circ, { showHidden: false, depth: null }) | ||||
| }) | ||||
| suite.add('util.inspect:          circular getters              ', function () { | ||||
|   inspect(circGetters, { showHidden: false, depth: null }) | ||||
| }) | ||||
| suite.add('util.inspect:          deep                          ', function () { | ||||
|   inspect(deep, { showHidden: false, depth: null }) | ||||
| }) | ||||
| suite.add('util.inspect:          deep circular                 ', function () { | ||||
|   inspect(deepCirc, { showHidden: false, depth: null }) | ||||
| }) | ||||
| suite.add('util.inspect:          large deep circular getters   ', function () { | ||||
|   inspect(deepCircGetters, { showHidden: false, depth: null }) | ||||
| }) | ||||
| suite.add('util.inspect:          deep non-conf circular getters', function () { | ||||
|   inspect(deepCircNonCongifurableGetters, { showHidden: false, depth: null }) | ||||
| }) | ||||
| 
 | ||||
| suite.add('\njson-stringify-safe:   simple object                 ', function () { | ||||
|   jsonStringifySafe(obj) | ||||
| }) | ||||
| suite.add('json-stringify-safe:   circular                      ', function () { | ||||
|   jsonStringifySafe(circ) | ||||
| }) | ||||
| suite.add('json-stringify-safe:   circular getters              ', function () { | ||||
|   jsonStringifySafe(circGetters) | ||||
| }) | ||||
| suite.add('json-stringify-safe:   deep                          ', function () { | ||||
|   jsonStringifySafe(deep) | ||||
| }) | ||||
| suite.add('json-stringify-safe:   deep circular                 ', function () { | ||||
|   jsonStringifySafe(deepCirc) | ||||
| }) | ||||
| suite.add('json-stringify-safe:   large deep circular getters   ', function () { | ||||
|   jsonStringifySafe(deepCircGetters) | ||||
| }) | ||||
| suite.add('json-stringify-safe:   deep non-conf circular getters', function () { | ||||
|   jsonStringifySafe(deepCircNonCongifurableGetters) | ||||
| }) | ||||
| 
 | ||||
| suite.add('\nfast-safe-stringify:   simple object                 ', function () { | ||||
|   fastSafeStringify(obj) | ||||
| }) | ||||
| suite.add('fast-safe-stringify:   circular                      ', function () { | ||||
|   fastSafeStringify(circ) | ||||
| }) | ||||
| suite.add('fast-safe-stringify:   circular getters              ', function () { | ||||
|   fastSafeStringify(circGetters) | ||||
| }) | ||||
| suite.add('fast-safe-stringify:   deep                          ', function () { | ||||
|   fastSafeStringify(deep) | ||||
| }) | ||||
| suite.add('fast-safe-stringify:   deep circular                 ', function () { | ||||
|   fastSafeStringify(deepCirc) | ||||
| }) | ||||
| suite.add('fast-safe-stringify:   large deep circular getters   ', function () { | ||||
|   fastSafeStringify(deepCircGetters) | ||||
| }) | ||||
| suite.add('fast-safe-stringify:   deep non-conf circular getters', function () { | ||||
|   fastSafeStringify(deepCircNonCongifurableGetters) | ||||
| }) | ||||
| 
 | ||||
| // add listeners
 | ||||
| suite.on('cycle', function (event) { | ||||
|   console.log(String(event.target)) | ||||
| }) | ||||
| 
 | ||||
| suite.on('complete', function () { | ||||
|   console.log('\nFastest is ' + this.filter('fastest').map('name')) | ||||
| }) | ||||
| 
 | ||||
| suite.run({ delay: 1, minSamples: 150 }) | ||||
							
								
								
									
										23
									
								
								node_modules/fast-safe-stringify/index.d.ts
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								node_modules/fast-safe-stringify/index.d.ts
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| declare function stringify( | ||||
|   value: any, | ||||
|   replacer?: (key: string, value: any) => any, | ||||
|   space?: string | number, | ||||
|   options?: { depthLimit: number | undefined; edgesLimit: number | undefined } | ||||
| ): string; | ||||
| 
 | ||||
| declare namespace stringify { | ||||
|   export function stable( | ||||
|     value: any, | ||||
|     replacer?: (key: string, value: any) => any, | ||||
|     space?: string | number, | ||||
|     options?: { depthLimit: number | undefined; edgesLimit: number | undefined } | ||||
|   ): string; | ||||
|   export function stableStringify( | ||||
|     value: any, | ||||
|     replacer?: (key: string, value: any) => any, | ||||
|     space?: string | number, | ||||
|     options?: { depthLimit: number | undefined; edgesLimit: number | undefined } | ||||
|   ): string; | ||||
| } | ||||
| 
 | ||||
| export default stringify; | ||||
							
								
								
									
										229
									
								
								node_modules/fast-safe-stringify/index.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								node_modules/fast-safe-stringify/index.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,229 @@ | |||
| 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) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										46
									
								
								node_modules/fast-safe-stringify/package.json
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								node_modules/fast-safe-stringify/package.json
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | |||
| { | ||||
|   "name": "fast-safe-stringify", | ||||
|   "version": "2.1.1", | ||||
|   "description": "Safely and quickly serialize JavaScript objects", | ||||
|   "keywords": [ | ||||
|     "stable", | ||||
|     "stringify", | ||||
|     "JSON", | ||||
|     "JSON.stringify", | ||||
|     "safe", | ||||
|     "serialize" | ||||
|   ], | ||||
|   "main": "index.js", | ||||
|   "scripts": { | ||||
|     "test": "standard && tap --no-esm test.js test-stable.js", | ||||
|     "benchmark": "node benchmark.js" | ||||
|   }, | ||||
|   "author": "David Mark Clements", | ||||
|   "contributors": [ | ||||
|     "Ruben Bridgewater", | ||||
|     "Matteo Collina", | ||||
|     "Ben Gourley", | ||||
|     "Gabriel Lesperance", | ||||
|     "Alex Liu", | ||||
|     "Christoph Walcher", | ||||
|     "Nicholas Young" | ||||
|   ], | ||||
|   "license": "MIT", | ||||
|   "typings": "index", | ||||
|   "devDependencies": { | ||||
|     "benchmark": "^2.1.4", | ||||
|     "clone": "^2.1.0", | ||||
|     "json-stringify-safe": "^5.0.1", | ||||
|     "standard": "^11.0.0", | ||||
|     "tap": "^12.0.0" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "git+https://github.com/davidmarkclements/fast-safe-stringify.git" | ||||
|   }, | ||||
|   "bugs": { | ||||
|     "url": "https://github.com/davidmarkclements/fast-safe-stringify/issues" | ||||
|   }, | ||||
|   "homepage": "https://github.com/davidmarkclements/fast-safe-stringify#readme", | ||||
|   "dependencies": {} | ||||
| } | ||||
							
								
								
									
										170
									
								
								node_modules/fast-safe-stringify/readme.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								node_modules/fast-safe-stringify/readme.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,170 @@ | |||
| # fast-safe-stringify | ||||
| 
 | ||||
| Safe and fast serialization alternative to [JSON.stringify][]. | ||||
| 
 | ||||
| Gracefully handles circular structures instead of throwing in most cases. | ||||
| It could return an error string if the circular object is too complex to analyze, | ||||
| e.g. in case there are proxies involved. | ||||
| 
 | ||||
| Provides a deterministic ("stable") version as well that will also gracefully | ||||
| handle circular structures. See the example below for further information. | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| The same as [JSON.stringify][]. | ||||
| 
 | ||||
| `stringify(value[, replacer[, space[, options]]])` | ||||
| 
 | ||||
| ```js | ||||
| const safeStringify = require('fast-safe-stringify') | ||||
| const o = { a: 1 } | ||||
| o.o = o | ||||
| 
 | ||||
| console.log(safeStringify(o)) | ||||
| // '{"a":1,"o":"[Circular]"}' | ||||
| console.log(JSON.stringify(o)) | ||||
| // TypeError: Converting circular structure to JSON | ||||
| 
 | ||||
| function replacer(key, value) { | ||||
|   console.log('Key:', JSON.stringify(key), 'Value:', JSON.stringify(value)) | ||||
|   // Remove the circular structure | ||||
|   if (value === '[Circular]') { | ||||
|     return | ||||
|   } | ||||
|   return value | ||||
| } | ||||
| 
 | ||||
| // those are also defaults limits when no options object is passed into safeStringify | ||||
| // configure it to lower the limit. | ||||
| const options = { | ||||
|   depthLimit: Number.MAX_SAFE_INTEGER, | ||||
|   edgesLimit: Number.MAX_SAFE_INTEGER | ||||
| }; | ||||
| 
 | ||||
| const serialized = safeStringify(o, replacer, 2, options) | ||||
| // Key: "" Value: {"a":1,"o":"[Circular]"} | ||||
| // Key: "a" Value: 1 | ||||
| // Key: "o" Value: "[Circular]" | ||||
| console.log(serialized) | ||||
| // { | ||||
| //  "a": 1 | ||||
| // } | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| Using the deterministic version also works the same: | ||||
| 
 | ||||
| ```js | ||||
| const safeStringify = require('fast-safe-stringify') | ||||
| const o = { b: 1, a: 0 } | ||||
| o.o = o | ||||
| 
 | ||||
| console.log(safeStringify(o)) | ||||
| // '{"b":1,"a":0,"o":"[Circular]"}' | ||||
| console.log(safeStringify.stableStringify(o)) | ||||
| // '{"a":0,"b":1,"o":"[Circular]"}' | ||||
| console.log(JSON.stringify(o)) | ||||
| // TypeError: Converting circular structure to JSON | ||||
| ``` | ||||
| 
 | ||||
| A faster and side-effect free implementation is available in the | ||||
| [safe-stable-stringify][] module. However it is still considered experimental | ||||
| due to a new and more complex implementation. | ||||
| 
 | ||||
| ### Replace strings constants | ||||
| 
 | ||||
| - `[Circular]` - when same reference is found | ||||
| - `[...]` - when some limit from options object is reached | ||||
| 
 | ||||
| ## Differences to JSON.stringify | ||||
| 
 | ||||
| In general the behavior is identical to [JSON.stringify][]. The [`replacer`][] | ||||
| and [`space`][] options are also available. | ||||
| 
 | ||||
| A few exceptions exist to [JSON.stringify][] while using [`toJSON`][] or | ||||
| [`replacer`][]: | ||||
| 
 | ||||
| ### Regular safe stringify | ||||
| 
 | ||||
| - Manipulating a circular structure of the passed in value in a `toJSON` or the | ||||
|   `replacer` is not possible! It is possible for any other value and property. | ||||
| 
 | ||||
| - In case a circular structure is detected and the [`replacer`][] is used it | ||||
|   will receive the string `[Circular]` as the argument instead of the circular | ||||
|   object itself. | ||||
| 
 | ||||
| ### Deterministic ("stable") safe stringify | ||||
| 
 | ||||
| - Manipulating the input object either in a [`toJSON`][] or the [`replacer`][] | ||||
|   function will not have any effect on the output. The output entirely relies on | ||||
|   the shape the input value had at the point passed to the stringify function! | ||||
| 
 | ||||
| - In case a circular structure is detected and the [`replacer`][] is used it | ||||
|   will receive the string `[Circular]` as the argument instead of the circular | ||||
|   object itself. | ||||
| 
 | ||||
| A side effect free variation without these limitations can be found as well | ||||
| ([`safe-stable-stringify`][]). It is also faster than the current | ||||
| implementation. It is still considered experimental due to a new and more | ||||
| complex implementation. | ||||
| 
 | ||||
| ## Benchmarks | ||||
| 
 | ||||
| Although not JSON, the Node.js `util.inspect` method can be used for similar | ||||
| purposes (e.g. logging) and also handles circular references. | ||||
| 
 | ||||
| Here we compare `fast-safe-stringify` with some alternatives: | ||||
| (Lenovo T450s with a i7-5600U CPU using Node.js 8.9.4) | ||||
| 
 | ||||
| ```md | ||||
| fast-safe-stringify:   simple object x 1,121,497 ops/sec ±0.75% (97 runs sampled) | ||||
| fast-safe-stringify:   circular      x 560,126 ops/sec ±0.64% (96 runs sampled) | ||||
| fast-safe-stringify:   deep          x 32,472 ops/sec ±0.57% (95 runs sampled) | ||||
| fast-safe-stringify:   deep circular x 32,513 ops/sec ±0.80% (92 runs sampled) | ||||
| 
 | ||||
| util.inspect:          simple object x 272,837 ops/sec ±1.48% (90 runs sampled) | ||||
| util.inspect:          circular      x 116,896 ops/sec ±1.19% (95 runs sampled) | ||||
| util.inspect:          deep          x 19,382 ops/sec ±0.66% (92 runs sampled) | ||||
| util.inspect:          deep circular x 18,717 ops/sec ±0.63% (96 runs sampled) | ||||
| 
 | ||||
| json-stringify-safe:   simple object x 233,621 ops/sec ±0.97% (94 runs sampled) | ||||
| json-stringify-safe:   circular      x 110,409 ops/sec ±1.85% (95 runs sampled) | ||||
| json-stringify-safe:   deep          x 8,705 ops/sec ±0.87% (96 runs sampled) | ||||
| json-stringify-safe:   deep circular x 8,336 ops/sec ±2.20% (93 runs sampled) | ||||
| ``` | ||||
| 
 | ||||
| For stable stringify comparisons, see the performance benchmarks in the | ||||
| [`safe-stable-stringify`][] readme. | ||||
| 
 | ||||
| ## Protip | ||||
| 
 | ||||
| Whether `fast-safe-stringify` or alternatives are used: if the use case | ||||
| consists of deeply nested objects without circular references the following | ||||
| pattern will give best results. | ||||
| Shallow or one level nested objects on the other hand will slow down with it. | ||||
| It is entirely dependant on the use case. | ||||
| 
 | ||||
| ```js | ||||
| const stringify = require('fast-safe-stringify') | ||||
| 
 | ||||
| function tryJSONStringify (obj) { | ||||
|   try { return JSON.stringify(obj) } catch (_) {} | ||||
| } | ||||
| 
 | ||||
| const serializedString = tryJSONStringify(deep) || stringify(deep) | ||||
| ``` | ||||
| 
 | ||||
| ## Acknowledgements | ||||
| 
 | ||||
| Sponsored by [nearForm](http://nearform.com) | ||||
| 
 | ||||
| ## License | ||||
| 
 | ||||
| MIT | ||||
| 
 | ||||
| [`replacer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The%20replacer%20parameter | ||||
| [`safe-stable-stringify`]: https://github.com/BridgeAR/safe-stable-stringify | ||||
| [`space`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The%20space%20argument | ||||
| [`toJSON`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON()_behavior | ||||
| [benchmark]: https://github.com/epoberezkin/fast-json-stable-stringify/blob/67f688f7441010cfef91a6147280cc501701e83b/benchmark | ||||
| [JSON.stringify]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify | ||||
							
								
								
									
										404
									
								
								node_modules/fast-safe-stringify/test-stable.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										404
									
								
								node_modules/fast-safe-stringify/test-stable.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,404 @@ | |||
| const test = require('tap').test | ||||
| const fss = require('./').stable | ||||
| const clone = require('clone') | ||||
| const s = JSON.stringify | ||||
| const stream = require('stream') | ||||
| 
 | ||||
| test('circular reference to root', function (assert) { | ||||
|   const fixture = { name: 'Tywin Lannister' } | ||||
|   fixture.circle = fixture | ||||
|   const expected = s({ circle: '[Circular]', name: 'Tywin Lannister' }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('circular getter reference to root', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     get circle () { | ||||
|       return fixture | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const expected = s({ circle: '[Circular]', name: 'Tywin Lannister' }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('nested circular reference to root', function (assert) { | ||||
|   const fixture = { name: 'Tywin Lannister' } | ||||
|   fixture.id = { circle: fixture } | ||||
|   const expected = s({ id: { circle: '[Circular]' }, name: 'Tywin Lannister' }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('child circular reference', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     child: { name: 'Tyrion Lannister' } | ||||
|   } | ||||
|   fixture.child.dinklage = fixture.child | ||||
|   const expected = s({ | ||||
|     child: { | ||||
|       dinklage: '[Circular]', | ||||
|       name: 'Tyrion Lannister' | ||||
|     }, | ||||
|     name: 'Tywin Lannister' | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('nested child circular reference', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     child: { name: 'Tyrion Lannister' } | ||||
|   } | ||||
|   fixture.child.actor = { dinklage: fixture.child } | ||||
|   const expected = s({ | ||||
|     child: { | ||||
|       actor: { dinklage: '[Circular]' }, | ||||
|       name: 'Tyrion Lannister' | ||||
|     }, | ||||
|     name: 'Tywin Lannister' | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('circular objects in an array', function (assert) { | ||||
|   const fixture = { name: 'Tywin Lannister' } | ||||
|   fixture.hand = [fixture, fixture] | ||||
|   const expected = s({ | ||||
|     hand: ['[Circular]', '[Circular]'], | ||||
|     name: 'Tywin Lannister' | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('nested circular references in an array', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     offspring: [{ name: 'Tyrion Lannister' }, { name: 'Cersei Lannister' }] | ||||
|   } | ||||
|   fixture.offspring[0].dinklage = fixture.offspring[0] | ||||
|   fixture.offspring[1].headey = fixture.offspring[1] | ||||
| 
 | ||||
|   const expected = s({ | ||||
|     name: 'Tywin Lannister', | ||||
|     offspring: [ | ||||
|       { dinklage: '[Circular]', name: 'Tyrion Lannister' }, | ||||
|       { headey: '[Circular]', name: 'Cersei Lannister' } | ||||
|     ] | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('circular arrays', function (assert) { | ||||
|   const fixture = [] | ||||
|   fixture.push(fixture, fixture) | ||||
|   const expected = s(['[Circular]', '[Circular]']) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('nested circular arrays', function (assert) { | ||||
|   const fixture = [] | ||||
|   fixture.push( | ||||
|     { name: 'Jon Snow', bastards: fixture }, | ||||
|     { name: 'Ramsay Bolton', bastards: fixture } | ||||
|   ) | ||||
|   const expected = s([ | ||||
|     { bastards: '[Circular]', name: 'Jon Snow' }, | ||||
|     { bastards: '[Circular]', name: 'Ramsay Bolton' } | ||||
|   ]) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('repeated non-circular references in objects', function (assert) { | ||||
|   const daenerys = { name: 'Daenerys Targaryen' } | ||||
|   const fixture = { | ||||
|     motherOfDragons: daenerys, | ||||
|     queenOfMeereen: daenerys | ||||
|   } | ||||
|   const expected = s(fixture) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('repeated non-circular references in arrays', function (assert) { | ||||
|   const daenerys = { name: 'Daenerys Targaryen' } | ||||
|   const fixture = [daenerys, daenerys] | ||||
|   const expected = s(fixture) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('double child circular reference', function (assert) { | ||||
|   // create circular reference
 | ||||
|   const child = { name: 'Tyrion Lannister' } | ||||
|   child.dinklage = child | ||||
| 
 | ||||
|   // include it twice in the fixture
 | ||||
|   const fixture = { name: 'Tywin Lannister', childA: child, childB: child } | ||||
|   const cloned = clone(fixture) | ||||
|   const expected = s({ | ||||
|     childA: { | ||||
|       dinklage: '[Circular]', | ||||
|       name: 'Tyrion Lannister' | ||||
|     }, | ||||
|     childB: { | ||||
|       dinklage: '[Circular]', | ||||
|       name: 'Tyrion Lannister' | ||||
|     }, | ||||
|     name: 'Tywin Lannister' | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
| 
 | ||||
|   // check if the fixture has not been modified
 | ||||
|   assert.same(fixture, cloned) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('child circular reference with toJSON', function (assert) { | ||||
|   // Create a test object that has an overridden `toJSON` property
 | ||||
|   TestObject.prototype.toJSON = function () { | ||||
|     return { special: 'case' } | ||||
|   } | ||||
|   function TestObject (content) {} | ||||
| 
 | ||||
|   // Creating a simple circular object structure
 | ||||
|   const parentObject = {} | ||||
|   parentObject.childObject = new TestObject() | ||||
|   parentObject.childObject.parentObject = parentObject | ||||
| 
 | ||||
|   // Creating a simple circular object structure
 | ||||
|   const otherParentObject = new TestObject() | ||||
|   otherParentObject.otherChildObject = {} | ||||
|   otherParentObject.otherChildObject.otherParentObject = otherParentObject | ||||
| 
 | ||||
|   // Making sure our original tests work
 | ||||
|   assert.same(parentObject.childObject.parentObject, parentObject) | ||||
|   assert.same( | ||||
|     otherParentObject.otherChildObject.otherParentObject, | ||||
|     otherParentObject | ||||
|   ) | ||||
| 
 | ||||
|   // Should both be idempotent
 | ||||
|   assert.equal(fss(parentObject), '{"childObject":{"special":"case"}}') | ||||
|   assert.equal(fss(otherParentObject), '{"special":"case"}') | ||||
| 
 | ||||
|   // Therefore the following assertion should be `true`
 | ||||
|   assert.same(parentObject.childObject.parentObject, parentObject) | ||||
|   assert.same( | ||||
|     otherParentObject.otherChildObject.otherParentObject, | ||||
|     otherParentObject | ||||
|   ) | ||||
| 
 | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('null object', function (assert) { | ||||
|   const expected = s(null) | ||||
|   const actual = fss(null) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('null property', function (assert) { | ||||
|   const expected = s({ f: null }) | ||||
|   const actual = fss({ f: null }) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('nested child circular reference in toJSON', function (assert) { | ||||
|   var circle = { some: 'data' } | ||||
|   circle.circle = circle | ||||
|   var a = { | ||||
|     b: { | ||||
|       toJSON: function () { | ||||
|         a.b = 2 | ||||
|         return '[Redacted]' | ||||
|       } | ||||
|     }, | ||||
|     baz: { | ||||
|       circle, | ||||
|       toJSON: function () { | ||||
|         a.baz = circle | ||||
|         return '[Redacted]' | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   var o = { | ||||
|     a, | ||||
|     bar: a | ||||
|   } | ||||
| 
 | ||||
|   const expected = s({ | ||||
|     a: { | ||||
|       b: '[Redacted]', | ||||
|       baz: '[Redacted]' | ||||
|     }, | ||||
|     bar: { | ||||
|       // TODO: This is a known limitation of the current implementation.
 | ||||
|       // The ideal result would be:
 | ||||
|       //
 | ||||
|       // b: 2,
 | ||||
|       // baz: {
 | ||||
|       //   circle: '[Circular]',
 | ||||
|       //   some: 'data'
 | ||||
|       // }
 | ||||
|       //
 | ||||
|       b: '[Redacted]', | ||||
|       baz: '[Redacted]' | ||||
|     } | ||||
|   }) | ||||
|   const actual = fss(o) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('circular getters are restored when stringified', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     get circle () { | ||||
|       return fixture | ||||
|     } | ||||
|   } | ||||
|   fss(fixture) | ||||
| 
 | ||||
|   assert.equal(fixture.circle, fixture) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('non-configurable circular getters use a replacer instead of markers', function (assert) { | ||||
|   const fixture = { name: 'Tywin Lannister' } | ||||
|   Object.defineProperty(fixture, 'circle', { | ||||
|     configurable: false, | ||||
|     get: function () { | ||||
|       return fixture | ||||
|     }, | ||||
|     enumerable: true | ||||
|   }) | ||||
| 
 | ||||
|   fss(fixture) | ||||
| 
 | ||||
|   assert.equal(fixture.circle, fixture) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('getter child circular reference', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     child: { | ||||
|       name: 'Tyrion Lannister', | ||||
|       get dinklage () { | ||||
|         return fixture.child | ||||
|       } | ||||
|     }, | ||||
|     get self () { | ||||
|       return fixture | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const expected = s({ | ||||
|     child: { | ||||
|       dinklage: '[Circular]', | ||||
|       name: 'Tyrion Lannister' | ||||
|     }, | ||||
|     name: 'Tywin Lannister', | ||||
|     self: '[Circular]' | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('Proxy throwing', function (assert) { | ||||
|   assert.plan(1) | ||||
|   const s = new stream.PassThrough() | ||||
|   s.resume() | ||||
|   s.write('', () => { | ||||
|     assert.end() | ||||
|   }) | ||||
|   const actual = fss({ s, p: new Proxy({}, { get () { throw new Error('kaboom') } }) }) | ||||
|   assert.equal(actual, '"[unable to serialize, circular reference is too complex to analyze]"') | ||||
| }) | ||||
| 
 | ||||
| test('depthLimit option - will replace deep objects', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     child: { | ||||
|       name: 'Tyrion Lannister' | ||||
|     }, | ||||
|     get self () { | ||||
|       return fixture | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const expected = s({ | ||||
|     child: '[...]', | ||||
|     name: 'Tywin Lannister', | ||||
|     self: '[Circular]' | ||||
|   }) | ||||
|   const actual = fss(fixture, undefined, undefined, { | ||||
|     depthLimit: 1, | ||||
|     edgesLimit: 1 | ||||
|   }) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('edgesLimit option - will replace deep objects', function (assert) { | ||||
|   const fixture = { | ||||
|     object: { | ||||
|       1: { test: 'test' }, | ||||
|       2: { test: 'test' }, | ||||
|       3: { test: 'test' }, | ||||
|       4: { test: 'test' } | ||||
|     }, | ||||
|     array: [ | ||||
|       { test: 'test' }, | ||||
|       { test: 'test' }, | ||||
|       { test: 'test' }, | ||||
|       { test: 'test' } | ||||
|     ], | ||||
|     get self () { | ||||
|       return fixture | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const expected = s({ | ||||
|     array: [{ test: 'test' }, { test: 'test' }, { test: 'test' }, '[...]'], | ||||
|     object: { | ||||
|       1: { test: 'test' }, | ||||
|       2: { test: 'test' }, | ||||
|       3: { test: 'test' }, | ||||
|       4: '[...]' | ||||
|     }, | ||||
|     self: '[Circular]' | ||||
|   }) | ||||
|   const actual = fss(fixture, undefined, undefined, { | ||||
|     depthLimit: 3, | ||||
|     edgesLimit: 3 | ||||
|   }) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
							
								
								
									
										397
									
								
								node_modules/fast-safe-stringify/test.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										397
									
								
								node_modules/fast-safe-stringify/test.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,397 @@ | |||
| const test = require('tap').test | ||||
| const fss = require('./') | ||||
| const clone = require('clone') | ||||
| const s = JSON.stringify | ||||
| const stream = require('stream') | ||||
| 
 | ||||
| test('circular reference to root', function (assert) { | ||||
|   const fixture = { name: 'Tywin Lannister' } | ||||
|   fixture.circle = fixture | ||||
|   const expected = s({ name: 'Tywin Lannister', circle: '[Circular]' }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('circular getter reference to root', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     get circle () { | ||||
|       return fixture | ||||
|     } | ||||
|   } | ||||
|   const expected = s({ name: 'Tywin Lannister', circle: '[Circular]' }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('nested circular reference to root', function (assert) { | ||||
|   const fixture = { name: 'Tywin Lannister' } | ||||
|   fixture.id = { circle: fixture } | ||||
|   const expected = s({ name: 'Tywin Lannister', id: { circle: '[Circular]' } }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('child circular reference', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     child: { name: 'Tyrion Lannister' } | ||||
|   } | ||||
|   fixture.child.dinklage = fixture.child | ||||
|   const expected = s({ | ||||
|     name: 'Tywin Lannister', | ||||
|     child: { | ||||
|       name: 'Tyrion Lannister', | ||||
|       dinklage: '[Circular]' | ||||
|     } | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('nested child circular reference', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     child: { name: 'Tyrion Lannister' } | ||||
|   } | ||||
|   fixture.child.actor = { dinklage: fixture.child } | ||||
|   const expected = s({ | ||||
|     name: 'Tywin Lannister', | ||||
|     child: { | ||||
|       name: 'Tyrion Lannister', | ||||
|       actor: { dinklage: '[Circular]' } | ||||
|     } | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('circular objects in an array', function (assert) { | ||||
|   const fixture = { name: 'Tywin Lannister' } | ||||
|   fixture.hand = [fixture, fixture] | ||||
|   const expected = s({ | ||||
|     name: 'Tywin Lannister', | ||||
|     hand: ['[Circular]', '[Circular]'] | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('nested circular references in an array', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     offspring: [{ name: 'Tyrion Lannister' }, { name: 'Cersei Lannister' }] | ||||
|   } | ||||
|   fixture.offspring[0].dinklage = fixture.offspring[0] | ||||
|   fixture.offspring[1].headey = fixture.offspring[1] | ||||
| 
 | ||||
|   const expected = s({ | ||||
|     name: 'Tywin Lannister', | ||||
|     offspring: [ | ||||
|       { name: 'Tyrion Lannister', dinklage: '[Circular]' }, | ||||
|       { name: 'Cersei Lannister', headey: '[Circular]' } | ||||
|     ] | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('circular arrays', function (assert) { | ||||
|   const fixture = [] | ||||
|   fixture.push(fixture, fixture) | ||||
|   const expected = s(['[Circular]', '[Circular]']) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('nested circular arrays', function (assert) { | ||||
|   const fixture = [] | ||||
|   fixture.push( | ||||
|     { name: 'Jon Snow', bastards: fixture }, | ||||
|     { name: 'Ramsay Bolton', bastards: fixture } | ||||
|   ) | ||||
|   const expected = s([ | ||||
|     { name: 'Jon Snow', bastards: '[Circular]' }, | ||||
|     { name: 'Ramsay Bolton', bastards: '[Circular]' } | ||||
|   ]) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('repeated non-circular references in objects', function (assert) { | ||||
|   const daenerys = { name: 'Daenerys Targaryen' } | ||||
|   const fixture = { | ||||
|     motherOfDragons: daenerys, | ||||
|     queenOfMeereen: daenerys | ||||
|   } | ||||
|   const expected = s(fixture) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('repeated non-circular references in arrays', function (assert) { | ||||
|   const daenerys = { name: 'Daenerys Targaryen' } | ||||
|   const fixture = [daenerys, daenerys] | ||||
|   const expected = s(fixture) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('double child circular reference', function (assert) { | ||||
|   // create circular reference
 | ||||
|   const child = { name: 'Tyrion Lannister' } | ||||
|   child.dinklage = child | ||||
| 
 | ||||
|   // include it twice in the fixture
 | ||||
|   const fixture = { name: 'Tywin Lannister', childA: child, childB: child } | ||||
|   const cloned = clone(fixture) | ||||
|   const expected = s({ | ||||
|     name: 'Tywin Lannister', | ||||
|     childA: { | ||||
|       name: 'Tyrion Lannister', | ||||
|       dinklage: '[Circular]' | ||||
|     }, | ||||
|     childB: { | ||||
|       name: 'Tyrion Lannister', | ||||
|       dinklage: '[Circular]' | ||||
|     } | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
| 
 | ||||
|   // check if the fixture has not been modified
 | ||||
|   assert.same(fixture, cloned) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('child circular reference with toJSON', function (assert) { | ||||
|   // Create a test object that has an overridden `toJSON` property
 | ||||
|   TestObject.prototype.toJSON = function () { | ||||
|     return { special: 'case' } | ||||
|   } | ||||
|   function TestObject (content) {} | ||||
| 
 | ||||
|   // Creating a simple circular object structure
 | ||||
|   const parentObject = {} | ||||
|   parentObject.childObject = new TestObject() | ||||
|   parentObject.childObject.parentObject = parentObject | ||||
| 
 | ||||
|   // Creating a simple circular object structure
 | ||||
|   const otherParentObject = new TestObject() | ||||
|   otherParentObject.otherChildObject = {} | ||||
|   otherParentObject.otherChildObject.otherParentObject = otherParentObject | ||||
| 
 | ||||
|   // Making sure our original tests work
 | ||||
|   assert.same(parentObject.childObject.parentObject, parentObject) | ||||
|   assert.same( | ||||
|     otherParentObject.otherChildObject.otherParentObject, | ||||
|     otherParentObject | ||||
|   ) | ||||
| 
 | ||||
|   // Should both be idempotent
 | ||||
|   assert.equal(fss(parentObject), '{"childObject":{"special":"case"}}') | ||||
|   assert.equal(fss(otherParentObject), '{"special":"case"}') | ||||
| 
 | ||||
|   // Therefore the following assertion should be `true`
 | ||||
|   assert.same(parentObject.childObject.parentObject, parentObject) | ||||
|   assert.same( | ||||
|     otherParentObject.otherChildObject.otherParentObject, | ||||
|     otherParentObject | ||||
|   ) | ||||
| 
 | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('null object', function (assert) { | ||||
|   const expected = s(null) | ||||
|   const actual = fss(null) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('null property', function (assert) { | ||||
|   const expected = s({ f: null }) | ||||
|   const actual = fss({ f: null }) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('nested child circular reference in toJSON', function (assert) { | ||||
|   const circle = { some: 'data' } | ||||
|   circle.circle = circle | ||||
|   const a = { | ||||
|     b: { | ||||
|       toJSON: function () { | ||||
|         a.b = 2 | ||||
|         return '[Redacted]' | ||||
|       } | ||||
|     }, | ||||
|     baz: { | ||||
|       circle, | ||||
|       toJSON: function () { | ||||
|         a.baz = circle | ||||
|         return '[Redacted]' | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   const o = { | ||||
|     a, | ||||
|     bar: a | ||||
|   } | ||||
| 
 | ||||
|   const expected = s({ | ||||
|     a: { | ||||
|       b: '[Redacted]', | ||||
|       baz: '[Redacted]' | ||||
|     }, | ||||
|     bar: { | ||||
|       b: 2, | ||||
|       baz: { | ||||
|         some: 'data', | ||||
|         circle: '[Circular]' | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
|   const actual = fss(o) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('circular getters are restored when stringified', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     get circle () { | ||||
|       return fixture | ||||
|     } | ||||
|   } | ||||
|   fss(fixture) | ||||
| 
 | ||||
|   assert.equal(fixture.circle, fixture) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('non-configurable circular getters use a replacer instead of markers', function (assert) { | ||||
|   const fixture = { name: 'Tywin Lannister' } | ||||
|   Object.defineProperty(fixture, 'circle', { | ||||
|     configurable: false, | ||||
|     get: function () { | ||||
|       return fixture | ||||
|     }, | ||||
|     enumerable: true | ||||
|   }) | ||||
| 
 | ||||
|   fss(fixture) | ||||
| 
 | ||||
|   assert.equal(fixture.circle, fixture) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('getter child circular reference are replaced instead of marked', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     child: { | ||||
|       name: 'Tyrion Lannister', | ||||
|       get dinklage () { | ||||
|         return fixture.child | ||||
|       } | ||||
|     }, | ||||
|     get self () { | ||||
|       return fixture | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const expected = s({ | ||||
|     name: 'Tywin Lannister', | ||||
|     child: { | ||||
|       name: 'Tyrion Lannister', | ||||
|       dinklage: '[Circular]' | ||||
|     }, | ||||
|     self: '[Circular]' | ||||
|   }) | ||||
|   const actual = fss(fixture) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('Proxy throwing', function (assert) { | ||||
|   assert.plan(1) | ||||
|   const s = new stream.PassThrough() | ||||
|   s.resume() | ||||
|   s.write('', () => { | ||||
|     assert.end() | ||||
|   }) | ||||
|   const actual = fss({ s, p: new Proxy({}, { get () { throw new Error('kaboom') } }) }) | ||||
|   assert.equal(actual, '"[unable to serialize, circular reference is too complex to analyze]"') | ||||
| }) | ||||
| 
 | ||||
| test('depthLimit option - will replace deep objects', function (assert) { | ||||
|   const fixture = { | ||||
|     name: 'Tywin Lannister', | ||||
|     child: { | ||||
|       name: 'Tyrion Lannister' | ||||
|     }, | ||||
|     get self () { | ||||
|       return fixture | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const expected = s({ | ||||
|     name: 'Tywin Lannister', | ||||
|     child: '[...]', | ||||
|     self: '[Circular]' | ||||
|   }) | ||||
|   const actual = fss(fixture, undefined, undefined, { | ||||
|     depthLimit: 1, | ||||
|     edgesLimit: 1 | ||||
|   }) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
| 
 | ||||
| test('edgesLimit option - will replace deep objects', function (assert) { | ||||
|   const fixture = { | ||||
|     object: { | ||||
|       1: { test: 'test' }, | ||||
|       2: { test: 'test' }, | ||||
|       3: { test: 'test' }, | ||||
|       4: { test: 'test' } | ||||
|     }, | ||||
|     array: [ | ||||
|       { test: 'test' }, | ||||
|       { test: 'test' }, | ||||
|       { test: 'test' }, | ||||
|       { test: 'test' } | ||||
|     ], | ||||
|     get self () { | ||||
|       return fixture | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const expected = s({ | ||||
|     object: { | ||||
|       1: { test: 'test' }, | ||||
|       2: { test: 'test' }, | ||||
|       3: { test: 'test' }, | ||||
|       4: '[...]' | ||||
|     }, | ||||
|     array: [{ test: 'test' }, { test: 'test' }, { test: 'test' }, '[...]'], | ||||
|     self: '[Circular]' | ||||
|   }) | ||||
|   const actual = fss(fixture, undefined, undefined, { | ||||
|     depthLimit: 3, | ||||
|     edgesLimit: 3 | ||||
|   }) | ||||
|   assert.equal(actual, expected) | ||||
|   assert.end() | ||||
| }) | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue