summaryrefslogtreecommitdiff
path: root/together/node_modules/fast-safe-stringify
diff options
context:
space:
mode:
authorMinteck <contact@minteck.org>2022-08-21 17:31:56 +0200
committerMinteck <contact@minteck.org>2022-08-21 17:31:56 +0200
commita2df9a69dcc14cb70118cda2ded499055e7ee358 (patch)
tree6dd283e4e9452d38bce81ddaaae49b5335755842 /together/node_modules/fast-safe-stringify
parent84dd0735820b16b60f600284d35183d76547a71f (diff)
downloadpluralconnect-a2df9a69dcc14cb70118cda2ded499055e7ee358.tar.gz
pluralconnect-a2df9a69dcc14cb70118cda2ded499055e7ee358.tar.bz2
pluralconnect-a2df9a69dcc14cb70118cda2ded499055e7ee358.zip
m. update
Diffstat (limited to 'together/node_modules/fast-safe-stringify')
-rw-r--r--together/node_modules/fast-safe-stringify/.travis.yml8
-rw-r--r--together/node_modules/fast-safe-stringify/CHANGELOG.md17
-rw-r--r--together/node_modules/fast-safe-stringify/LICENSE23
-rw-r--r--together/node_modules/fast-safe-stringify/benchmark.js137
-rw-r--r--together/node_modules/fast-safe-stringify/index.d.ts23
-rw-r--r--together/node_modules/fast-safe-stringify/index.js229
-rw-r--r--together/node_modules/fast-safe-stringify/package.json46
-rw-r--r--together/node_modules/fast-safe-stringify/readme.md170
-rw-r--r--together/node_modules/fast-safe-stringify/test-stable.js404
-rw-r--r--together/node_modules/fast-safe-stringify/test.js397
10 files changed, 1454 insertions, 0 deletions
diff --git a/together/node_modules/fast-safe-stringify/.travis.yml b/together/node_modules/fast-safe-stringify/.travis.yml
new file mode 100644
index 0000000..2b06d25
--- /dev/null
+++ b/together/node_modules/fast-safe-stringify/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+sudo: false
+node_js:
+- '4'
+- '6'
+- '8'
+- '9'
+- '10'
diff --git a/together/node_modules/fast-safe-stringify/CHANGELOG.md b/together/node_modules/fast-safe-stringify/CHANGELOG.md
new file mode 100644
index 0000000..55f2d08
--- /dev/null
+++ b/together/node_modules/fast-safe-stringify/CHANGELOG.md
@@ -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
diff --git a/together/node_modules/fast-safe-stringify/LICENSE b/together/node_modules/fast-safe-stringify/LICENSE
new file mode 100644
index 0000000..d310c2d
--- /dev/null
+++ b/together/node_modules/fast-safe-stringify/LICENSE
@@ -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.
diff --git a/together/node_modules/fast-safe-stringify/benchmark.js b/together/node_modules/fast-safe-stringify/benchmark.js
new file mode 100644
index 0000000..7ba5e9f
--- /dev/null
+++ b/together/node_modules/fast-safe-stringify/benchmark.js
@@ -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 })
diff --git a/together/node_modules/fast-safe-stringify/index.d.ts b/together/node_modules/fast-safe-stringify/index.d.ts
new file mode 100644
index 0000000..9a9b1f0
--- /dev/null
+++ b/together/node_modules/fast-safe-stringify/index.d.ts
@@ -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;
diff --git a/together/node_modules/fast-safe-stringify/index.js b/together/node_modules/fast-safe-stringify/index.js
new file mode 100644
index 0000000..ecf7e51
--- /dev/null
+++ b/together/node_modules/fast-safe-stringify/index.js
@@ -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)
+ }
+}
diff --git a/together/node_modules/fast-safe-stringify/package.json b/together/node_modules/fast-safe-stringify/package.json
new file mode 100644
index 0000000..206a591
--- /dev/null
+++ b/together/node_modules/fast-safe-stringify/package.json
@@ -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": {}
+}
diff --git a/together/node_modules/fast-safe-stringify/readme.md b/together/node_modules/fast-safe-stringify/readme.md
new file mode 100644
index 0000000..47179c9
--- /dev/null
+++ b/together/node_modules/fast-safe-stringify/readme.md
@@ -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
diff --git a/together/node_modules/fast-safe-stringify/test-stable.js b/together/node_modules/fast-safe-stringify/test-stable.js
new file mode 100644
index 0000000..c55b95c
--- /dev/null
+++ b/together/node_modules/fast-safe-stringify/test-stable.js
@@ -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()
+})
diff --git a/together/node_modules/fast-safe-stringify/test.js b/together/node_modules/fast-safe-stringify/test.js
new file mode 100644
index 0000000..a4170e9
--- /dev/null
+++ b/together/node_modules/fast-safe-stringify/test.js
@@ -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()
+})