copy-anything
Advanced tools
Comparing version 1.4.0 to 1.5.0
@@ -5,2 +5,17 @@ 'use strict'; | ||
function assignProp(carry, key, newVal, originalObject, nonenumerable) { | ||
var propType = originalObject.propertyIsEnumerable(key) | ||
? 'enumerable' | ||
: 'nonenumerable'; | ||
if (propType === 'enumerable') | ||
carry[key] = newVal; | ||
if (nonenumerable && propType === 'nonenumerable') { | ||
Object.defineProperty(carry, key, { | ||
value: newVal, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
}); | ||
} | ||
} | ||
/** | ||
@@ -11,13 +26,21 @@ * Copy (clone) an object and all its props recursively to get rid of any prop referenced of the original object. Arrays are also cloned, however objects inside arrays are still linked. | ||
* @param {*} target Target can be anything | ||
* @param {*} options Options can be `props` or `nonenumerable`. | ||
* @returns {*} the target with replaced values | ||
*/ | ||
function copy(target) { | ||
function copy(target, options) { | ||
if (options === void 0) { options = { props: null, nonenumerable: false }; } | ||
if (isWhat.isArray(target)) | ||
return target.map(function (i) { return copy(i); }); | ||
return target.map(function (i) { return copy(i, options); }); | ||
if (!isWhat.isPlainObject(target)) | ||
return target; | ||
return Object.keys(target) | ||
.reduce(function (carry, key) { | ||
var props = Object.getOwnPropertyNames(target); | ||
var symbols = Object.getOwnPropertySymbols(target); | ||
return props.concat(symbols).reduce(function (carry, key) { | ||
if (isWhat.isArray(options.props) && !options.props.includes(key)) { | ||
return carry; | ||
} | ||
// @ts-ignore | ||
var val = target[key]; | ||
carry[key] = copy(val); | ||
var newVal = copy(val, options); | ||
assignProp(carry, key, newVal, target, options.nonenumerable); | ||
return carry; | ||
@@ -24,0 +47,0 @@ }, {}); |
import { isArray, isPlainObject } from 'is-what'; | ||
function assignProp(carry, key, newVal, originalObject, nonenumerable) { | ||
var propType = originalObject.propertyIsEnumerable(key) | ||
? 'enumerable' | ||
: 'nonenumerable'; | ||
if (propType === 'enumerable') | ||
carry[key] = newVal; | ||
if (nonenumerable && propType === 'nonenumerable') { | ||
Object.defineProperty(carry, key, { | ||
value: newVal, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
}); | ||
} | ||
} | ||
/** | ||
@@ -8,13 +23,21 @@ * Copy (clone) an object and all its props recursively to get rid of any prop referenced of the original object. Arrays are also cloned, however objects inside arrays are still linked. | ||
* @param {*} target Target can be anything | ||
* @param {*} options Options can be `props` or `nonenumerable`. | ||
* @returns {*} the target with replaced values | ||
*/ | ||
function copy(target) { | ||
function copy(target, options) { | ||
if (options === void 0) { options = { props: null, nonenumerable: false }; } | ||
if (isArray(target)) | ||
return target.map(function (i) { return copy(i); }); | ||
return target.map(function (i) { return copy(i, options); }); | ||
if (!isPlainObject(target)) | ||
return target; | ||
return Object.keys(target) | ||
.reduce(function (carry, key) { | ||
var props = Object.getOwnPropertyNames(target); | ||
var symbols = Object.getOwnPropertySymbols(target); | ||
return props.concat(symbols).reduce(function (carry, key) { | ||
if (isArray(options.props) && !options.props.includes(key)) { | ||
return carry; | ||
} | ||
// @ts-ignore | ||
var val = target[key]; | ||
carry[key] = copy(val); | ||
var newVal = copy(val, options); | ||
assignProp(carry, key, newVal, target, options.nonenumerable); | ||
return carry; | ||
@@ -21,0 +44,0 @@ }, {}); |
{ | ||
"name": "copy-anything", | ||
"version": "1.4.0", | ||
"version": "1.5.0", | ||
"description": "An optimised way to copy'ing an object. A small and simple integration", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.cjs.js", |
@@ -19,2 +19,4 @@ # Copy anything 🎭 | ||
- works with arrays and objects in arrays! | ||
- supports symbols | ||
- can copy non-enumerable props as well | ||
- **does not break special class instances** ‼️ | ||
@@ -53,2 +55,4 @@ | ||
> Please note, by default copy-anything does not copy non-enumerable props. If you need to copy those, see the instructions further down below. | ||
## Works with arrays | ||
@@ -59,4 +63,2 @@ | ||
```js | ||
import copy from 'copy-anything' | ||
const original = [{name: 'Squirtle'}] | ||
@@ -74,2 +76,35 @@ const copy = copy(original) | ||
## Non-enumerable | ||
By default, copy-anything only copies enumerable properties. If you also want to copy non-enumerable properties you can do so by passing that as an option. | ||
```js | ||
const original = {name: 'Bulbasaur'} | ||
// bulbasaur's ID is non-enumerable | ||
Object.defineProperty(original, 'id', { | ||
value: '001', | ||
writable: true, | ||
enumerable: false, | ||
configurable: true | ||
}) | ||
const copy1 = copy(original) | ||
const copy2 = copy(original, {nonenumerable: true}) | ||
(copy1.id === undefined) | ||
(copy2.id === '001') | ||
``` | ||
## Limit to specific props | ||
You can limit to specific props. | ||
```js | ||
const original = {name: 'Flareon', type: ['fire'], id: '136'} | ||
const copy = copy(original, {props: ['name']}) | ||
(copy === {name: 'Flareon'}) | ||
``` | ||
> Please note, if the props you have specified are non-enumerable, you will also need to pass `{nonenumerable: true}`. | ||
## Source code | ||
@@ -76,0 +111,0 @@ |
import { isPlainObject, isArray } from 'is-what' | ||
function assignProp (carry, key, newVal, originalObject, nonenumerable) { | ||
const propType = originalObject.propertyIsEnumerable(key) | ||
? 'enumerable' | ||
: 'nonenumerable' | ||
if (propType === 'enumerable') carry[key] = newVal | ||
if (nonenumerable && propType === 'nonenumerable') { | ||
Object.defineProperty(carry, key, { | ||
value: newVal, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
}) | ||
} | ||
} | ||
export type Options = {props: any[], nonenumerable: boolean} | ||
/** | ||
@@ -8,13 +25,24 @@ * Copy (clone) an object and all its props recursively to get rid of any prop referenced of the original object. Arrays are also cloned, however objects inside arrays are still linked. | ||
* @param {*} target Target can be anything | ||
* @param {*} options Options can be `props` or `nonenumerable`. | ||
* @returns {*} the target with replaced values | ||
*/ | ||
export default function copy (target: any): any { | ||
if (isArray(target)) return target.map(i => copy(i)) | ||
export default function copy ( | ||
target: any, | ||
options: Options = {props: null, nonenumerable: false} | ||
): any { | ||
if (isArray(target)) return target.map(i => copy(i, options)) | ||
if (!isPlainObject(target)) return target | ||
return Object.keys(target) | ||
const props = Object.getOwnPropertyNames(target) | ||
const symbols = Object.getOwnPropertySymbols(target) | ||
return [...props, ...symbols] | ||
.reduce((carry, key) => { | ||
if (isArray(options.props) && !options.props.includes(key)) { | ||
return carry | ||
} | ||
// @ts-ignore | ||
const val = target[key] | ||
carry[key] = copy(val) | ||
const newVal = copy(val, options) | ||
assignProp(carry, key, newVal, target, options.nonenumerable) | ||
return carry | ||
}, {}) | ||
} |
@@ -115,1 +115,124 @@ import test from 'ava' | ||
}) | ||
test('symbols as keys', t => { | ||
let res, target | ||
const mySymbol = Symbol('mySymbol') | ||
target = { value: 42, [mySymbol]: 'hello' } | ||
res = copy(target) | ||
// change original | ||
target.value = 1 | ||
target[mySymbol] = 2 | ||
t.is(res.value, 42) | ||
t.is(res[mySymbol], 'hello') | ||
t.is(target.value, 1) | ||
t.is(target[mySymbol], 2) | ||
}) | ||
test('nonenumerable keys - turned on', t => { | ||
let target, res | ||
const mySymbol = Symbol('mySymbol') | ||
target = { value: 42 } | ||
Object.defineProperty(target, 'id', { | ||
value: 1, | ||
writable: true, | ||
enumerable: false, | ||
configurable: true | ||
}) | ||
Object.defineProperty(target, mySymbol, { | ||
value: 'original', | ||
writable: true, | ||
enumerable: false, | ||
configurable: true | ||
}) | ||
res = copy(target, {nonenumerable: true}) | ||
// change original | ||
target.id = 100 | ||
target[mySymbol] = 'new' | ||
target.value = 300 | ||
t.is(res.value, 42) | ||
t.is(res.id, 1) | ||
t.is(res[mySymbol], 'original') | ||
t.is(Object.keys(res).length, 1) | ||
t.true(Object.keys(res).includes('value')) | ||
t.is(target.id, 100) | ||
t.is(target[mySymbol], 'new') | ||
t.is(target.value, 300) | ||
t.is(Object.keys(target).length, 1) | ||
}) | ||
test('nonenumerable keys - turned off', t => { | ||
let target, res | ||
const mySymbol = Symbol('mySymbol') | ||
target = { value: 42 } | ||
Object.defineProperty(target, 'id', { | ||
value: 1, | ||
writable: true, | ||
enumerable: false, | ||
configurable: true | ||
}) | ||
Object.defineProperty(target, mySymbol, { | ||
value: 'original', | ||
writable: true, | ||
enumerable: false, | ||
configurable: true | ||
}) | ||
res = copy(target) | ||
// change original | ||
t.is(res.value, 42) | ||
t.is(res.id, undefined) | ||
t.is(res[mySymbol], undefined) | ||
}) | ||
test('specific props', t => { | ||
let target, res | ||
const mySymbol = Symbol('mySymbol') | ||
const mySymbol2 = Symbol('mySymbol') | ||
target = { value: 42, value2: 24 } | ||
Object.defineProperty(target, 'id', { | ||
value: 1, | ||
writable: true, | ||
enumerable: false, | ||
configurable: true | ||
}) | ||
Object.defineProperty(target, mySymbol, { | ||
value: 'original', | ||
writable: true, | ||
enumerable: false, | ||
configurable: true | ||
}) | ||
Object.defineProperty(target, 'id2', { | ||
value: 2, | ||
writable: true, | ||
enumerable: false, | ||
configurable: true | ||
}) | ||
Object.defineProperty(target, mySymbol2, { | ||
value: 'original2', | ||
writable: true, | ||
enumerable: false, | ||
configurable: true | ||
}) | ||
// only enumerable | ||
res = copy(target, {props: [mySymbol, 'value', 'id']}) | ||
t.is(res.value, 42) | ||
t.is(res.id, undefined) | ||
t.is(res[mySymbol], undefined) | ||
t.is(res.value2, undefined) | ||
t.is(res.id2, undefined) | ||
t.is(res[mySymbol2], undefined) | ||
t.is(Object.keys(res).length, 1) | ||
t.true(Object.keys(res).includes('value')) | ||
t.is(Object.keys(target).length, 2) | ||
// non-enumerable included | ||
res = copy(target, {props: [mySymbol, 'value', 'id'], nonenumerable: true}) | ||
t.is(res.value, 42) | ||
t.is(res.id, 1) | ||
t.is(res[mySymbol], 'original') | ||
t.is(res.value2, undefined) | ||
t.is(res.id2, undefined) | ||
t.is(res[mySymbol2], undefined) | ||
t.is(Object.keys(res).length, 1) | ||
t.true(Object.keys(res).includes('value')) | ||
t.is(Object.keys(target).length, 2) | ||
}) |
@@ -0,1 +1,5 @@ | ||
export declare type Options = { | ||
props: any[]; | ||
nonenumerable: boolean; | ||
}; | ||
/** | ||
@@ -6,4 +10,5 @@ * Copy (clone) an object and all its props recursively to get rid of any prop referenced of the original object. Arrays are also cloned, however objects inside arrays are still linked. | ||
* @param {*} target Target can be anything | ||
* @param {*} options Options can be `props` or `nonenumerable`. | ||
* @returns {*} the target with replaced values | ||
*/ | ||
export default function copy(target: any): any; | ||
export default function copy(target: any, options?: Options): any; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
21629
485
124