mirror of
https://github.com/xfarrow/blink
synced 2025-06-27 09:03:02 +02:00
Change endpoint from persons to people
This commit is contained in:
8
backend/apis/nodejs/node_modules/fast-safe-stringify/.travis.yml
generated
vendored
Normal file
8
backend/apis/nodejs/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
backend/apis/nodejs/node_modules/fast-safe-stringify/CHANGELOG.md
generated
vendored
Normal file
17
backend/apis/nodejs/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
backend/apis/nodejs/node_modules/fast-safe-stringify/LICENSE
generated
vendored
Normal file
23
backend/apis/nodejs/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
backend/apis/nodejs/node_modules/fast-safe-stringify/benchmark.js
generated
vendored
Normal file
137
backend/apis/nodejs/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
backend/apis/nodejs/node_modules/fast-safe-stringify/index.d.ts
generated
vendored
Normal file
23
backend/apis/nodejs/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
backend/apis/nodejs/node_modules/fast-safe-stringify/index.js
generated
vendored
Normal file
229
backend/apis/nodejs/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
backend/apis/nodejs/node_modules/fast-safe-stringify/package.json
generated
vendored
Normal file
46
backend/apis/nodejs/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
backend/apis/nodejs/node_modules/fast-safe-stringify/readme.md
generated
vendored
Normal file
170
backend/apis/nodejs/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
backend/apis/nodejs/node_modules/fast-safe-stringify/test-stable.js
generated
vendored
Normal file
404
backend/apis/nodejs/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
backend/apis/nodejs/node_modules/fast-safe-stringify/test.js
generated
vendored
Normal file
397
backend/apis/nodejs/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()
|
||||
})
|
Reference in New Issue
Block a user