update socials section
This commit is contained in:
21
node_modules/rfdc/.github/workflows/ci.yml
generated
vendored
Normal file
21
node_modules/rfdc/.github/workflows/ci.yml
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
node-version: [8.x, 10.x, 12.x, 14.x, 16.x, 18.x, 20.x, 22.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm install
|
||||
- run: npm run ci
|
15
node_modules/rfdc/LICENSE
generated
vendored
Normal file
15
node_modules/rfdc/LICENSE
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
Copyright 2019 "David Mark Clements <david.mark.clements@gmail.com>"
|
||||
|
||||
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.
|
3
node_modules/rfdc/default.js
generated
vendored
Normal file
3
node_modules/rfdc/default.js
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = require('./index.js')()
|
13
node_modules/rfdc/index.d.ts
generated
vendored
Normal file
13
node_modules/rfdc/index.d.ts
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
declare namespace rfdc {
|
||||
interface Options {
|
||||
proto?: boolean;
|
||||
circles?: boolean;
|
||||
constructorHandlers?: ConstructorHandlerConfig[];
|
||||
}
|
||||
}
|
||||
type Constructor<T> = {new(...args: any[]): T};
|
||||
type ConstructorHandlerConfig<T = any> = [Constructor<T>, (o: T) => T];
|
||||
|
||||
declare function rfdc(options?: rfdc.Options): <T>(input: T) => T;
|
||||
|
||||
export = rfdc;
|
198
node_modules/rfdc/index.js
generated
vendored
Normal file
198
node_modules/rfdc/index.js
generated
vendored
Normal file
@ -0,0 +1,198 @@
|
||||
'use strict'
|
||||
module.exports = rfdc
|
||||
|
||||
function copyBuffer (cur) {
|
||||
if (cur instanceof Buffer) {
|
||||
return Buffer.from(cur)
|
||||
}
|
||||
|
||||
return new cur.constructor(cur.buffer.slice(), cur.byteOffset, cur.length)
|
||||
}
|
||||
|
||||
function rfdc (opts) {
|
||||
opts = opts || {}
|
||||
if (opts.circles) return rfdcCircles(opts)
|
||||
|
||||
const constructorHandlers = new Map()
|
||||
constructorHandlers.set(Date, (o) => new Date(o))
|
||||
constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)))
|
||||
constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)))
|
||||
if (opts.constructorHandlers) {
|
||||
for (const handler of opts.constructorHandlers) {
|
||||
constructorHandlers.set(handler[0], handler[1])
|
||||
}
|
||||
}
|
||||
|
||||
let handler = null
|
||||
|
||||
return opts.proto ? cloneProto : clone
|
||||
|
||||
function cloneArray (a, fn) {
|
||||
const keys = Object.keys(a)
|
||||
const a2 = new Array(keys.length)
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const k = keys[i]
|
||||
const cur = a[k]
|
||||
if (typeof cur !== 'object' || cur === null) {
|
||||
a2[k] = cur
|
||||
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
||||
a2[k] = handler(cur, fn)
|
||||
} else if (ArrayBuffer.isView(cur)) {
|
||||
a2[k] = copyBuffer(cur)
|
||||
} else {
|
||||
a2[k] = fn(cur)
|
||||
}
|
||||
}
|
||||
return a2
|
||||
}
|
||||
|
||||
function clone (o) {
|
||||
if (typeof o !== 'object' || o === null) return o
|
||||
if (Array.isArray(o)) return cloneArray(o, clone)
|
||||
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
||||
return handler(o, clone)
|
||||
}
|
||||
const o2 = {}
|
||||
for (const k in o) {
|
||||
if (Object.hasOwnProperty.call(o, k) === false) continue
|
||||
const cur = o[k]
|
||||
if (typeof cur !== 'object' || cur === null) {
|
||||
o2[k] = cur
|
||||
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
||||
o2[k] = handler(cur, clone)
|
||||
} else if (ArrayBuffer.isView(cur)) {
|
||||
o2[k] = copyBuffer(cur)
|
||||
} else {
|
||||
o2[k] = clone(cur)
|
||||
}
|
||||
}
|
||||
return o2
|
||||
}
|
||||
|
||||
function cloneProto (o) {
|
||||
if (typeof o !== 'object' || o === null) return o
|
||||
if (Array.isArray(o)) return cloneArray(o, cloneProto)
|
||||
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
||||
return handler(o, cloneProto)
|
||||
}
|
||||
const o2 = {}
|
||||
for (const k in o) {
|
||||
const cur = o[k]
|
||||
if (typeof cur !== 'object' || cur === null) {
|
||||
o2[k] = cur
|
||||
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
||||
o2[k] = handler(cur, cloneProto)
|
||||
} else if (ArrayBuffer.isView(cur)) {
|
||||
o2[k] = copyBuffer(cur)
|
||||
} else {
|
||||
o2[k] = cloneProto(cur)
|
||||
}
|
||||
}
|
||||
return o2
|
||||
}
|
||||
}
|
||||
|
||||
function rfdcCircles (opts) {
|
||||
const refs = []
|
||||
const refsNew = []
|
||||
|
||||
const constructorHandlers = new Map()
|
||||
constructorHandlers.set(Date, (o) => new Date(o))
|
||||
constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)))
|
||||
constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)))
|
||||
if (opts.constructorHandlers) {
|
||||
for (const handler of opts.constructorHandlers) {
|
||||
constructorHandlers.set(handler[0], handler[1])
|
||||
}
|
||||
}
|
||||
|
||||
let handler = null
|
||||
return opts.proto ? cloneProto : clone
|
||||
|
||||
function cloneArray (a, fn) {
|
||||
const keys = Object.keys(a)
|
||||
const a2 = new Array(keys.length)
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const k = keys[i]
|
||||
const cur = a[k]
|
||||
if (typeof cur !== 'object' || cur === null) {
|
||||
a2[k] = cur
|
||||
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
||||
a2[k] = handler(cur, fn)
|
||||
} else if (ArrayBuffer.isView(cur)) {
|
||||
a2[k] = copyBuffer(cur)
|
||||
} else {
|
||||
const index = refs.indexOf(cur)
|
||||
if (index !== -1) {
|
||||
a2[k] = refsNew[index]
|
||||
} else {
|
||||
a2[k] = fn(cur)
|
||||
}
|
||||
}
|
||||
}
|
||||
return a2
|
||||
}
|
||||
|
||||
function clone (o) {
|
||||
if (typeof o !== 'object' || o === null) return o
|
||||
if (Array.isArray(o)) return cloneArray(o, clone)
|
||||
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
||||
return handler(o, clone)
|
||||
}
|
||||
const o2 = {}
|
||||
refs.push(o)
|
||||
refsNew.push(o2)
|
||||
for (const k in o) {
|
||||
if (Object.hasOwnProperty.call(o, k) === false) continue
|
||||
const cur = o[k]
|
||||
if (typeof cur !== 'object' || cur === null) {
|
||||
o2[k] = cur
|
||||
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
||||
o2[k] = handler(cur, clone)
|
||||
} else if (ArrayBuffer.isView(cur)) {
|
||||
o2[k] = copyBuffer(cur)
|
||||
} else {
|
||||
const i = refs.indexOf(cur)
|
||||
if (i !== -1) {
|
||||
o2[k] = refsNew[i]
|
||||
} else {
|
||||
o2[k] = clone(cur)
|
||||
}
|
||||
}
|
||||
}
|
||||
refs.pop()
|
||||
refsNew.pop()
|
||||
return o2
|
||||
}
|
||||
|
||||
function cloneProto (o) {
|
||||
if (typeof o !== 'object' || o === null) return o
|
||||
if (Array.isArray(o)) return cloneArray(o, cloneProto)
|
||||
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
||||
return handler(o, cloneProto)
|
||||
}
|
||||
const o2 = {}
|
||||
refs.push(o)
|
||||
refsNew.push(o2)
|
||||
for (const k in o) {
|
||||
const cur = o[k]
|
||||
if (typeof cur !== 'object' || cur === null) {
|
||||
o2[k] = cur
|
||||
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
||||
o2[k] = handler(cur, cloneProto)
|
||||
} else if (ArrayBuffer.isView(cur)) {
|
||||
o2[k] = copyBuffer(cur)
|
||||
} else {
|
||||
const i = refs.indexOf(cur)
|
||||
if (i !== -1) {
|
||||
o2[k] = refsNew[i]
|
||||
} else {
|
||||
o2[k] = cloneProto(cur)
|
||||
}
|
||||
}
|
||||
}
|
||||
refs.pop()
|
||||
refsNew.pop()
|
||||
return o2
|
||||
}
|
||||
}
|
13
node_modules/rfdc/index.test-d.ts
generated
vendored
Normal file
13
node_modules/rfdc/index.test-d.ts
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
import { expectType } from 'tsd';
|
||||
import rfdc = require('.');
|
||||
|
||||
const clone = rfdc();
|
||||
|
||||
expectType<number>(clone(5));
|
||||
expectType<{ lorem: string }>(clone({ lorem: "ipsum" }));
|
||||
|
||||
const cloneHandlers = rfdc({
|
||||
constructorHandlers: [
|
||||
[RegExp, (o) => new RegExp(o)],
|
||||
],
|
||||
})
|
73
node_modules/rfdc/package.json
generated
vendored
Normal file
73
node_modules/rfdc/package.json
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "rfdc",
|
||||
"version": "1.4.1",
|
||||
"description": "Really Fast Deep Clone",
|
||||
"main": "index.js",
|
||||
"exports": {
|
||||
".": "./index.js",
|
||||
"./default": "./default.js"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tap -R min test && npm run lint",
|
||||
"bench": "node benchmark",
|
||||
"lint": "standard --fix",
|
||||
"cov": "tap --100 test",
|
||||
"cov-ui": "tap --coverage-report=html test",
|
||||
"ci": "standard && tap --100 --coverage-report=text-lcov test | codecov --pipe"
|
||||
},
|
||||
"keywords": [
|
||||
"object",
|
||||
"obj",
|
||||
"properties",
|
||||
"clone",
|
||||
"copy",
|
||||
"deep",
|
||||
"recursive",
|
||||
"key",
|
||||
"keys",
|
||||
"values",
|
||||
"prop",
|
||||
"deep-clone",
|
||||
"deepclone",
|
||||
"deep-copy",
|
||||
"deepcopy",
|
||||
"fast",
|
||||
"performance",
|
||||
"performant",
|
||||
"fastclone",
|
||||
"fastcopy",
|
||||
"fast-clone",
|
||||
"fast-deep-clone",
|
||||
"fast-copy",
|
||||
"fast-deep-copy"
|
||||
],
|
||||
"author": "David Mark Clements <david.clements@nearform.com>",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"clone-deep": "^4.0.1",
|
||||
"codecov": "^3.4.0",
|
||||
"deep-copy": "^1.4.2",
|
||||
"fast-copy": "^1.2.1",
|
||||
"fastbench": "^1.0.1",
|
||||
"fastest-json-copy": "^1.0.1",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"nano-copy": "^0.1.0",
|
||||
"plain-object-clone": "^1.1.0",
|
||||
"ramda": "^0.27.1",
|
||||
"standard": "^17.0.0",
|
||||
"tap": "^12.0.1",
|
||||
"tsd": "^0.7.4"
|
||||
},
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"dependencies": {},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/davidmarkclements/rfdc.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/davidmarkclements/rfdc/issues"
|
||||
},
|
||||
"homepage": "https://github.com/davidmarkclements/rfdc#readme"
|
||||
}
|
181
node_modules/rfdc/readme.md
generated
vendored
Normal file
181
node_modules/rfdc/readme.md
generated
vendored
Normal file
@ -0,0 +1,181 @@
|
||||
# rfdc
|
||||
|
||||
Really Fast Deep Clone
|
||||
|
||||
|
||||
[](https://travis-ci.org/davidmarkclements/rfdc)
|
||||
[](https://codecov.io/gh/davidmarkclements/rfdc)
|
||||
[](http://standardjs.com/)
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const clone = require('rfdc')()
|
||||
clone({a: 1, b: {c: 2}}) // => {a: 1, b: {c: 2}}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `require('rfdc')(opts = { proto: false, circles: false, constructorHandlers: [] }) => clone(obj) => obj2`
|
||||
|
||||
#### `proto` option
|
||||
|
||||
Copy prototype properties as well as own properties into the new object.
|
||||
|
||||
It's marginally faster to allow enumerable properties on the prototype
|
||||
to be copied into the cloned object (not onto it's prototype, directly onto the object).
|
||||
|
||||
To explain by way of code:
|
||||
|
||||
```js
|
||||
require('rfdc')({ proto: false })(Object.create({a: 1})) // => {}
|
||||
require('rfdc')({ proto: true })(Object.create({a: 1})) // => {a: 1}
|
||||
```
|
||||
|
||||
Setting `proto` to `true` will provide an additional 2% performance boost.
|
||||
|
||||
#### `circles` option
|
||||
|
||||
Keeping track of circular references will slow down performance with an
|
||||
additional 25% overhead. Even if an object doesn't have any circular references,
|
||||
the tracking overhead is the cost. By default if an object with a circular
|
||||
reference is passed to `rfdc`, it will throw (similar to how `JSON.stringify` \
|
||||
would throw).
|
||||
|
||||
Use the `circles` option to detect and preserve circular references in the
|
||||
object. If performance is important, try removing the circular reference from
|
||||
the object (set to `undefined`) and then add it back manually after cloning
|
||||
instead of using this option.
|
||||
|
||||
#### `constructorHandlers` option
|
||||
|
||||
Sometimes consumers may want to add custom clone behaviour for particular classes
|
||||
(for example `RegExp` or `ObjectId`, which aren't supported out-of-the-box).
|
||||
|
||||
This can be done by passing `constructorHandlers`, which takes an array of tuples,
|
||||
where the first item is the class to match, and the second item is a function that
|
||||
takes the input and returns a cloned output:
|
||||
|
||||
```js
|
||||
const clone = require('rfdc')({
|
||||
constructorHandlers: [
|
||||
[RegExp, (o) => new RegExp(o)],
|
||||
]
|
||||
})
|
||||
|
||||
clone({r: /foo/}) // => {r: /foo/}
|
||||
```
|
||||
|
||||
**NOTE**: For performance reasons, the handlers will only match an instance of the
|
||||
*exact* class (not a subclass). Subclasses will need to be added separately if they
|
||||
also need special clone behaviour.
|
||||
|
||||
### `default` import
|
||||
It is also possible to directly import the clone function with all options set
|
||||
to their default:
|
||||
|
||||
```js
|
||||
const clone = require("rfdc/default")
|
||||
clone({a: 1, b: {c: 2}}) // => {a: 1, b: {c: 2}}
|
||||
```
|
||||
|
||||
### Types
|
||||
|
||||
`rfdc` clones all JSON types:
|
||||
|
||||
* `Object`
|
||||
* `Array`
|
||||
* `Number`
|
||||
* `String`
|
||||
* `null`
|
||||
|
||||
With additional support for:
|
||||
|
||||
* `Date` (copied)
|
||||
* `undefined` (copied)
|
||||
* `Buffer` (copied)
|
||||
* `TypedArray` (copied)
|
||||
* `Map` (copied)
|
||||
* `Set` (copied)
|
||||
* `Function` (referenced)
|
||||
* `AsyncFunction` (referenced)
|
||||
* `GeneratorFunction` (referenced)
|
||||
* `arguments` (copied to a normal object)
|
||||
|
||||
All other types have output values that match the output
|
||||
of `JSON.parse(JSON.stringify(o))`.
|
||||
|
||||
For instance:
|
||||
|
||||
```js
|
||||
const rfdc = require('rfdc')()
|
||||
const err = Error()
|
||||
err.code = 1
|
||||
JSON.parse(JSON.stringify(e)) // {code: 1}
|
||||
rfdc(e) // {code: 1}
|
||||
|
||||
JSON.parse(JSON.stringify({rx: /foo/})) // {rx: {}}
|
||||
rfdc({rx: /foo/}) // {rx: {}}
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
```sh
|
||||
npm run bench
|
||||
```
|
||||
|
||||
```
|
||||
benchDeepCopy*100: 671.675ms
|
||||
benchLodashCloneDeep*100: 1.574s
|
||||
benchCloneDeep*100: 936.792ms
|
||||
benchFastCopy*100: 822.668ms
|
||||
benchFastestJsonCopy*100: 363.898ms // See note below
|
||||
benchPlainObjectClone*100: 556.635ms
|
||||
benchNanoCopy*100: 770.234ms
|
||||
benchRamdaClone*100: 2.695s
|
||||
benchJsonParseJsonStringify*100: 2.290s // JSON.parse(JSON.stringify(obj))
|
||||
benchRfdc*100: 412.818ms
|
||||
benchRfdcProto*100: 424.076ms
|
||||
benchRfdcCircles*100: 443.357ms
|
||||
benchRfdcCirclesProto*100: 465.053ms
|
||||
```
|
||||
|
||||
It is true that [fastest-json-copy](https://www.npmjs.com/package/fastest-json-copy) may be faster, BUT it has such huge limitations that it is rarely useful. For example, it treats things like `Date` and `Map` instances the same as empty `{}`. It can't handle circular references. [plain-object-clone](https://www.npmjs.com/package/plain-object-clone) is also really limited in capability.
|
||||
|
||||
## Tests
|
||||
|
||||
```sh
|
||||
npm test
|
||||
```
|
||||
|
||||
```
|
||||
169 passing (342.514ms)
|
||||
```
|
||||
|
||||
### Coverage
|
||||
|
||||
```sh
|
||||
npm run cov
|
||||
```
|
||||
|
||||
```
|
||||
----------|----------|----------|----------|----------|-------------------|
|
||||
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
|
||||
----------|----------|----------|----------|----------|-------------------|
|
||||
All files | 100 | 100 | 100 | 100 | |
|
||||
index.js | 100 | 100 | 100 | 100 | |
|
||||
----------|----------|----------|----------|----------|-------------------|
|
||||
```
|
||||
|
||||
### `__proto__` own property copying
|
||||
|
||||
`rfdc` works the same way as `Object.assign` when it comes to copying `['__proto__']` (e.g. when
|
||||
an object has an own property key called '__proto__'). It results in the target object
|
||||
prototype object being set per the value of the `['__proto__']` own property.
|
||||
|
||||
For detailed write-up on how a way to handle this security-wise see https://www.fastify.io/docs/latest/Guides/Prototype-Poisoning/.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
306
node_modules/rfdc/test/index.js
generated
vendored
Normal file
306
node_modules/rfdc/test/index.js
generated
vendored
Normal file
@ -0,0 +1,306 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const rfdc = require('..')
|
||||
const cloneDefault = require('../default')
|
||||
const clone = rfdc()
|
||||
const cloneProto = rfdc({ proto: true })
|
||||
const cloneCircles = rfdc({ circles: true })
|
||||
const cloneCirclesProto = rfdc({ circles: true, proto: true })
|
||||
|
||||
const rnd = (max) => Math.round(Math.random() * max)
|
||||
|
||||
types(clone, 'default')
|
||||
types(cloneProto, 'proto option')
|
||||
types(cloneCircles, 'circles option')
|
||||
types(cloneCirclesProto, 'circles and proto option')
|
||||
|
||||
test('default – does not copy proto properties', async ({ is }) => {
|
||||
is(clone(Object.create({ a: 1 })).a, undefined, 'value not copied')
|
||||
})
|
||||
test('default – shorthand import', async ({ same }) => {
|
||||
same(
|
||||
clone(Object.create({ a: 1 })),
|
||||
cloneDefault(Object.create({ a: 1 })),
|
||||
'import equals clone with default options'
|
||||
)
|
||||
})
|
||||
test('proto option – copies enumerable proto properties', async ({ is }) => {
|
||||
is(cloneProto(Object.create({ a: 1 })).a, 1, 'value copied')
|
||||
})
|
||||
test('circles option - circular object', async ({ same, is, isNot }) => {
|
||||
const o = { nest: { a: 1, b: 2 } }
|
||||
o.circular = o
|
||||
same(cloneCircles(o), o, 'same values')
|
||||
isNot(cloneCircles(o), o, 'different objects')
|
||||
isNot(cloneCircles(o).nest, o.nest, 'different nested objects')
|
||||
const c = cloneCircles(o)
|
||||
is(c.circular, c, 'circular references point to copied parent')
|
||||
isNot(c.circular, o, 'circular references do not point to original parent')
|
||||
})
|
||||
test('circles option – deep circular object', async ({ same, is, isNot }) => {
|
||||
const o = { nest: { a: 1, b: 2 } }
|
||||
o.nest.circular = o
|
||||
same(cloneCircles(o), o, 'same values')
|
||||
isNot(cloneCircles(o), o, 'different objects')
|
||||
isNot(cloneCircles(o).nest, o.nest, 'different nested objects')
|
||||
const c = cloneCircles(o)
|
||||
is(c.nest.circular, c, 'circular references point to copied parent')
|
||||
isNot(
|
||||
c.nest.circular,
|
||||
o,
|
||||
'circular references do not point to original parent'
|
||||
)
|
||||
})
|
||||
test('circles option alone – does not copy proto properties', async ({
|
||||
is
|
||||
}) => {
|
||||
is(cloneCircles(Object.create({ a: 1 })).a, undefined, 'value not copied')
|
||||
})
|
||||
test('circles and proto option – copies enumerable proto properties', async ({
|
||||
is
|
||||
}) => {
|
||||
is(cloneCirclesProto(Object.create({ a: 1 })).a, 1, 'value copied')
|
||||
})
|
||||
test('circles and proto option - circular object', async ({
|
||||
same,
|
||||
is,
|
||||
isNot
|
||||
}) => {
|
||||
const o = { nest: { a: 1, b: 2 } }
|
||||
o.circular = o
|
||||
same(cloneCirclesProto(o), o, 'same values')
|
||||
isNot(cloneCirclesProto(o), o, 'different objects')
|
||||
isNot(cloneCirclesProto(o).nest, o.nest, 'different nested objects')
|
||||
const c = cloneCirclesProto(o)
|
||||
is(c.circular, c, 'circular references point to copied parent')
|
||||
isNot(c.circular, o, 'circular references do not point to original parent')
|
||||
})
|
||||
test('circles and proto option – deep circular object', async ({
|
||||
same,
|
||||
is,
|
||||
isNot
|
||||
}) => {
|
||||
const o = { nest: { a: 1, b: 2 } }
|
||||
o.nest.circular = o
|
||||
same(cloneCirclesProto(o), o, 'same values')
|
||||
isNot(cloneCirclesProto(o), o, 'different objects')
|
||||
isNot(cloneCirclesProto(o).nest, o.nest, 'different nested objects')
|
||||
const c = cloneCirclesProto(o)
|
||||
is(c.nest.circular, c, 'circular references point to copied parent')
|
||||
isNot(
|
||||
c.nest.circular,
|
||||
o,
|
||||
'circular references do not point to original parent'
|
||||
)
|
||||
})
|
||||
test('circles and proto option – deep circular array', async ({
|
||||
same,
|
||||
is,
|
||||
isNot
|
||||
}) => {
|
||||
const o = { nest: [1, 2] }
|
||||
o.nest.push(o)
|
||||
same(cloneCirclesProto(o), o, 'same values')
|
||||
isNot(cloneCirclesProto(o), o, 'different objects')
|
||||
isNot(cloneCirclesProto(o).nest, o.nest, 'different nested objects')
|
||||
const c = cloneCirclesProto(o)
|
||||
is(c.nest[2], c, 'circular references point to copied parent')
|
||||
isNot(c.nest[2], o, 'circular references do not point to original parent')
|
||||
})
|
||||
test('custom constructor handler', async ({ same, ok, isNot }) => {
|
||||
class Foo {
|
||||
constructor (s) {
|
||||
this.s = s
|
||||
}
|
||||
}
|
||||
const data = { foo: new Foo('foo') }
|
||||
const cloned = rfdc({ constructorHandlers: [[Foo, (o) => new Foo(o.s)]] })(data)
|
||||
ok(cloned.foo instanceof Foo)
|
||||
same(cloned.foo.s, data.foo.s, 'same values')
|
||||
isNot(cloned.foo, data.foo, 'different objects')
|
||||
})
|
||||
test('custom RegExp handler', async ({ same, ok, isNot }) => {
|
||||
const data = { regex: /foo/ }
|
||||
const cloned = rfdc({ constructorHandlers: [[RegExp, (o) => new RegExp(o)]] })(data)
|
||||
isNot(cloned.regex, data.regex, 'different objects')
|
||||
ok(cloned.regex.test('foo'))
|
||||
})
|
||||
|
||||
function types (clone, label) {
|
||||
test(label + ' – number', async ({ is }) => {
|
||||
is(clone(42), 42, 'same value')
|
||||
})
|
||||
test(label + ' – string', async ({ is }) => {
|
||||
is(clone('str'), 'str', 'same value')
|
||||
})
|
||||
test(label + ' – boolean', async ({ is }) => {
|
||||
is(clone(true), true, 'same value')
|
||||
})
|
||||
test(label + ' – function', async ({ is }) => {
|
||||
const fn = () => {}
|
||||
is(clone(fn), fn, 'same function')
|
||||
})
|
||||
test(label + ' – async function', async ({ is }) => {
|
||||
const fn = async () => {}
|
||||
is(clone(fn), fn, 'same function')
|
||||
})
|
||||
test(label + ' – generator function', async ({ is }) => {
|
||||
const fn = function * () {}
|
||||
is(clone(fn), fn, 'same function')
|
||||
})
|
||||
test(label + ' – date', async ({ is, isNot }) => {
|
||||
const date = new Date()
|
||||
is(+clone(date), +date, 'same value')
|
||||
isNot(clone(date), date, 'different object')
|
||||
})
|
||||
test(label + ' – null', async ({ is }) => {
|
||||
is(clone(null), null, 'same value')
|
||||
})
|
||||
test(label + ' – shallow object', async ({ same, isNot }) => {
|
||||
const o = { a: 1, b: 2 }
|
||||
same(clone(o), o, 'same values')
|
||||
isNot(clone(o), o, 'different object')
|
||||
})
|
||||
test(label + ' – shallow array', async ({ same, isNot }) => {
|
||||
const o = [1, 2]
|
||||
same(clone(o), o, 'same values')
|
||||
isNot(clone(o), o, 'different arrays')
|
||||
})
|
||||
test(label + ' – deep object', async ({ same, isNot }) => {
|
||||
const o = { nest: { a: 1, b: 2 } }
|
||||
same(clone(o), o, 'same values')
|
||||
isNot(clone(o), o, 'different objects')
|
||||
isNot(clone(o).nest, o.nest, 'different nested objects')
|
||||
})
|
||||
test(label + ' – deep array', async ({ same, isNot }) => {
|
||||
const o = [{ a: 1, b: 2 }, [3]]
|
||||
same(clone(o), o, 'same values')
|
||||
isNot(clone(o), o, 'different arrays')
|
||||
isNot(clone(o)[0], o[0], 'different array elements')
|
||||
isNot(clone(o)[1], o[1], 'different array elements')
|
||||
})
|
||||
test(label + ' – nested number', async ({ is }) => {
|
||||
is(clone({ a: 1 }).a, 1, 'same value')
|
||||
})
|
||||
test(label + ' – nested string', async ({ is }) => {
|
||||
is(clone({ s: 'str' }).s, 'str', 'same value')
|
||||
})
|
||||
test(label + ' – nested boolean', async ({ is }) => {
|
||||
is(clone({ b: true }).b, true, 'same value')
|
||||
})
|
||||
test(label + ' – nested function', async ({ is }) => {
|
||||
const fn = () => {}
|
||||
is(clone({ fn }).fn, fn, 'same function')
|
||||
})
|
||||
test(label + ' – nested async function', async ({ is }) => {
|
||||
const fn = async () => {}
|
||||
is(clone({ fn }).fn, fn, 'same function')
|
||||
})
|
||||
test(label + ' – nested generator function', async ({ is }) => {
|
||||
const fn = function * () {}
|
||||
is(clone({ fn }).fn, fn, 'same function')
|
||||
})
|
||||
test(label + ' – nested date', async ({ is, isNot }) => {
|
||||
const date = new Date()
|
||||
is(+clone({ d: date }).d, +date, 'same value')
|
||||
isNot(clone({ d: date }).d, date, 'different object')
|
||||
})
|
||||
test(label + ' – nested date in array', async ({ is, isNot }) => {
|
||||
const date = new Date()
|
||||
is(+clone({ d: [date] }).d[0], +date, 'same value')
|
||||
isNot(clone({ d: [date] }).d[0], date, 'different object')
|
||||
is(+cloneCircles({ d: [date] }).d[0], +date, 'same value')
|
||||
isNot(cloneCircles({ d: [date] }).d, date, 'different object')
|
||||
})
|
||||
test(label + ' – nested null', async ({ is }) => {
|
||||
is(clone({ n: null }).n, null, 'same value')
|
||||
})
|
||||
test(label + ' – arguments', async ({ isNot, same }) => {
|
||||
function fn (...args) {
|
||||
same(clone(arguments), args, 'same values')
|
||||
isNot(clone(arguments), arguments, 'different object')
|
||||
}
|
||||
fn(1, 2, 3)
|
||||
})
|
||||
test(`${label} copies buffers from object correctly`, async ({ ok, is, isNot }) => {
|
||||
const input = Date.now().toString(36)
|
||||
const inputBuffer = Buffer.from(input)
|
||||
const clonedBuffer = clone({ a: inputBuffer }).a
|
||||
ok(Buffer.isBuffer(clonedBuffer), 'cloned value is buffer')
|
||||
isNot(clonedBuffer, inputBuffer, 'cloned buffer is not same as input buffer')
|
||||
is(clonedBuffer.toString(), input, 'cloned buffer content is correct')
|
||||
})
|
||||
test(`${label} copies buffers from arrays correctly`, async ({ ok, is, isNot }) => {
|
||||
const input = Date.now().toString(36)
|
||||
const inputBuffer = Buffer.from(input)
|
||||
const [clonedBuffer] = clone([inputBuffer])
|
||||
ok(Buffer.isBuffer(clonedBuffer), 'cloned value is buffer')
|
||||
isNot(clonedBuffer, inputBuffer, 'cloned buffer is not same as input buffer')
|
||||
is(clonedBuffer.toString(), input, 'cloned buffer content is correct')
|
||||
})
|
||||
test(`${label} copies TypedArrays from object correctly`, async ({ ok, is, isNot }) => {
|
||||
const [input1, input2] = [rnd(10), rnd(10)]
|
||||
const buffer = new ArrayBuffer(8)
|
||||
const int32View = new Int32Array(buffer)
|
||||
int32View[0] = input1
|
||||
int32View[1] = input2
|
||||
const cloned = clone({ a: int32View }).a
|
||||
ok(cloned instanceof Int32Array, 'cloned value is instance of class')
|
||||
isNot(cloned, int32View, 'cloned value is not same as input value')
|
||||
is(cloned[0], input1, 'cloned value content is correct')
|
||||
is(cloned[1], input2, 'cloned value content is correct')
|
||||
})
|
||||
test(`${label} copies TypedArrays from array correctly`, async ({ ok, is, isNot }) => {
|
||||
const [input1, input2] = [rnd(10), rnd(10)]
|
||||
const buffer = new ArrayBuffer(16)
|
||||
const int32View = new Int32Array(buffer)
|
||||
int32View[0] = input1
|
||||
int32View[1] = input2
|
||||
const [cloned] = clone([int32View])
|
||||
ok(cloned instanceof Int32Array, 'cloned value is instance of class')
|
||||
isNot(cloned, int32View, 'cloned value is not same as input value')
|
||||
is(cloned[0], input1, 'cloned value content is correct')
|
||||
is(cloned[1], input2, 'cloned value content is correct')
|
||||
})
|
||||
test(`${label} copies complex TypedArrays`, async ({ ok, deepEqual, is, isNot }) => {
|
||||
const [input1, input2, input3] = [rnd(10), rnd(10), rnd(10)]
|
||||
const buffer = new ArrayBuffer(4)
|
||||
const view1 = new Int8Array(buffer, 0, 2)
|
||||
const view2 = new Int8Array(buffer, 2, 2)
|
||||
const view3 = new Int8Array(buffer)
|
||||
view1[0] = input1
|
||||
view2[0] = input2
|
||||
view3[3] = input3
|
||||
const cloned = clone({ view1, view2, view3 })
|
||||
ok(cloned.view1 instanceof Int8Array, 'cloned value is instance of class')
|
||||
ok(cloned.view2 instanceof Int8Array, 'cloned value is instance of class')
|
||||
ok(cloned.view3 instanceof Int8Array, 'cloned value is instance of class')
|
||||
isNot(cloned.view1, view1, 'cloned value is not same as input value')
|
||||
isNot(cloned.view2, view2, 'cloned value is not same as input value')
|
||||
isNot(cloned.view3, view3, 'cloned value is not same as input value')
|
||||
deepEqual(Array.from(cloned.view1), [input1, 0], 'cloned value content is correct')
|
||||
deepEqual(Array.from(cloned.view2), [input2, input3], 'cloned value content is correct')
|
||||
deepEqual(Array.from(cloned.view3), [input1, 0, input2, input3], 'cloned value content is correct')
|
||||
})
|
||||
test(`${label} - maps`, async ({ same, isNot }) => {
|
||||
const map = new Map([['a', 1]])
|
||||
same(Array.from(clone(map)), [['a', 1]], 'same value')
|
||||
isNot(clone(map), map, 'different object')
|
||||
})
|
||||
test(`${label} - sets`, async ({ same, isNot }) => {
|
||||
const set = new Set([1])
|
||||
same(Array.from(clone(set)), [1])
|
||||
isNot(clone(set), set, 'different object')
|
||||
})
|
||||
test(`${label} - nested maps`, async ({ same, isNot }) => {
|
||||
const data = { m: new Map([['a', 1]]) }
|
||||
same(Array.from(clone(data).m), [['a', 1]], 'same value')
|
||||
isNot(clone(data).m, data.m, 'different object')
|
||||
})
|
||||
test(`${label} - nested sets`, async ({ same, isNot }) => {
|
||||
const data = { s: new Set([1]) }
|
||||
same(Array.from(clone(data).s), [1], 'same value')
|
||||
isNot(clone(data).s, data.s, 'different object')
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user