8889841cfull/index.js000066600000003146150435264720007173 0ustar00function set(obj, key, val) { if (typeof val.value === 'object') val.value = klona(val.value); if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === '__proto__') { Object.defineProperty(obj, key, val); } else obj[key] = val.value; } function klona(x) { if (typeof x !== 'object') return x; var i=0, k, list, tmp, str=Object.prototype.toString.call(x); if (str === '[object Object]') { tmp = Object.create(x.__proto__ || null); } else if (str === '[object Array]') { tmp = Array(x.length); } else if (str === '[object Set]') { tmp = new Set; x.forEach(function (val) { tmp.add(klona(val)); }); } else if (str === '[object Map]') { tmp = new Map; x.forEach(function (val, key) { tmp.set(klona(key), klona(val)); }); } else if (str === '[object Date]') { tmp = new Date(+x); } else if (str === '[object RegExp]') { tmp = new RegExp(x.source, x.flags); } else if (str === '[object DataView]') { tmp = new x.constructor( klona(x.buffer) ); } else if (str === '[object ArrayBuffer]') { tmp = x.slice(0); } else if (str.slice(-6) === 'Array]') { // ArrayBuffer.isView(x) // ~> `new` bcuz `Buffer.slice` => ref tmp = new x.constructor(x); } if (tmp) { for (list=Object.getOwnPropertySymbols(x); i < list.length; i++) { set(tmp, list[i], Object.getOwnPropertyDescriptor(x, list[i])); } for (i=0, list=Object.getOwnPropertyNames(x); i < list.length; i++) { if (Object.hasOwnProperty.call(tmp, k=list[i]) && tmp[k] === x[k]) continue; set(tmp, k, Object.getOwnPropertyDescriptor(x, k)); } } return tmp || x; } exports.klona = klona;full/index.mjs000066600000003126150435264720007346 0ustar00function set(obj, key, val) { if (typeof val.value === 'object') val.value = klona(val.value); if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === '__proto__') { Object.defineProperty(obj, key, val); } else obj[key] = val.value; } export function klona(x) { if (typeof x !== 'object') return x; var i=0, k, list, tmp, str=Object.prototype.toString.call(x); if (str === '[object Object]') { tmp = Object.create(x.__proto__ || null); } else if (str === '[object Array]') { tmp = Array(x.length); } else if (str === '[object Set]') { tmp = new Set; x.forEach(function (val) { tmp.add(klona(val)); }); } else if (str === '[object Map]') { tmp = new Map; x.forEach(function (val, key) { tmp.set(klona(key), klona(val)); }); } else if (str === '[object Date]') { tmp = new Date(+x); } else if (str === '[object RegExp]') { tmp = new RegExp(x.source, x.flags); } else if (str === '[object DataView]') { tmp = new x.constructor( klona(x.buffer) ); } else if (str === '[object ArrayBuffer]') { tmp = x.slice(0); } else if (str.slice(-6) === 'Array]') { // ArrayBuffer.isView(x) // ~> `new` bcuz `Buffer.slice` => ref tmp = new x.constructor(x); } if (tmp) { for (list=Object.getOwnPropertySymbols(x); i < list.length; i++) { set(tmp, list[i], Object.getOwnPropertyDescriptor(x, list[i])); } for (i=0, list=Object.getOwnPropertyNames(x); i < list.length; i++) { if (Object.hasOwnProperty.call(tmp, k=list[i]) && tmp[k] === x[k]) continue; set(tmp, k, Object.getOwnPropertyDescriptor(x, k)); } } return tmp || x; } full/index.min.js000066600000002267150435264720007760 0ustar00!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.klona={})}(this,(function(e){function t(e,t,r){"object"==typeof r.value&&(r.value=o(r.value)),r.enumerable&&!r.get&&!r.set&&r.configurable&&r.writable&&"__proto__"!==t?e[t]=r.value:Object.defineProperty(e,t,r)}function o(e){if("object"!=typeof e)return e;var r,n,c,a=0,f=Object.prototype.toString.call(e);if("[object Object]"===f?c=Object.create(e.__proto__||null):"[object Array]"===f?c=Array(e.length):"[object Set]"===f?(c=new Set,e.forEach((function(e){c.add(o(e))}))):"[object Map]"===f?(c=new Map,e.forEach((function(e,t){c.set(o(t),o(e))}))):"[object Date]"===f?c=new Date(+e):"[object RegExp]"===f?c=new RegExp(e.source,e.flags):"[object DataView]"===f?c=new e.constructor(o(e.buffer)):"[object ArrayBuffer]"===f?c=e.slice(0):"Array]"===f.slice(-6)&&(c=new e.constructor(e)),c){for(n=Object.getOwnPropertySymbols(e);a(input: T): T;readme.md000066600000015760150435264720006350 0ustar00
klona
version CI downloads codecov
A tiny (240B to 501B) and fast utility to "deep clone" Objects, Arrays, Dates, RegExps, and more!
## Features * Super tiny and [performant](#benchmarks) * Deep clone / recursive copies * Safely handles complex data types
_Array, Date, Map, Object, RegExp, Set, TypedArray, and more_ Unlike a "shallow copy" (eg, `Object.assign`), a "deep clone" recursively traverses a source input and copies its _values_ — instead of _references_ to its values — into a new instance of that input. The result is a structurally equivalent clone that operates independently of the original source and controls its own values. > **Why "klona"?** It's "clone" in Swedish.
> **What's with the sheep?** [Dolly](https://en.wikipedia.org/wiki/Dolly_(sheep)). ## Install ``` $ npm install --save klona ``` ## Modes There are multiple "versions" of `klona` available, which allows you to bring only the functionality you need! #### `klona/json` > **Size (gzip):** 240 bytes
> **Availability:** [CommonJS](https://unpkg.com/klona/json/index.js), [ES Module](https://unpkg.com/klona/json/index.mjs), [UMD](https://unpkg.com/klona/json/index.min.js)
> **Ability:** JSON data types ```js import { klona } from 'klona/json'; ``` #### `klona/lite` > **Size (gzip):** 354 bytes
> **Availability:** [CommonJS](https://unpkg.com/klona/lite/index.js), [ES Module](https://unpkg.com/klona/lite/index.mjs), [UMD](https://unpkg.com/klona/lite/index.min.js)
> **Ability:** extends `klona/json` with support for custom class, Date, and RegExp ```js import { klona } from 'klona/lite'; ``` #### `klona` > **Size (gzip):** 451 bytes
> **Availability:** [CommonJS](https://unpkg.com/klona/dist/index.js), [ES Module](https://unpkg.com/klona/dist/index.mjs), [UMD](https://unpkg.com/klona/dist/index.min.js)
> **Ability:** extends `klona/lite` with support for Map, Set, DataView, ArrayBuffer, TypedArray ```js import { klona } from 'klona'; ``` #### `klona/full` > **Size (gzip):** 501 bytes
> **Availability:** [CommonJS](https://unpkg.com/klona/full/index.js), [ES Module](https://unpkg.com/klona/full/index.mjs), [UMD](https://unpkg.com/klona/full/index.min.js)
> **Ability:** extends `klona` with support for Symbol properties and and non-enumerable properties ```js import { klona } from 'klona/full'; ``` ## Usage ```js import { klona } from 'klona'; const input = { foo: 1, bar: { baz: 2, bat: { hello: 'world' } } }; const output = klona(input); // exact copy of original assert.deepStrictEqual(input, output); // applying deep updates... output.bar.bat.hola = 'mundo'; output.bar.baz = 99; // ...doesn't affect source! console.log( JSON.stringify(input, null, 2) ); // { // "foo": 1, // "bar": { // "baz": 2, // "bat": { // "hello": "world" // } // } // } ``` ## API ### klona(input) Returns: `typeof input` Returns a deep copy/clone of the input. ## Benchmarks > Running Node v12.18.3 The benchmarks can be found in the [`/bench`](/bench) directory. They are separated into multiple categories: * `JSON` – compares an array of objects comprised of JSON data types (`String`, `Number`, `null`, `Array`, `Object`) * `LITE` – like `JSON`, but adds `RegExp`, `Date` and `undefined` values * `DEFAULT` – object with `RegExp`, `Date`, `Array`, `Map`, `Set`, custom class, `Int8Array`, `DataView`, `Buffer` values * `FULL` – like `DEFAULT`, but adds `Symbol` and non-enumerable properties > **Important:** Only candidates that pass validation step(s) are listed.
However, `lodash` and `clone` are kept to highlight important differences. > **Note:** The `clone/include` candidate refers to its [`includeNonEnumerable` option](https://www.npmjs.com/package/clone#api) enabled. ``` Load times: lodash/clonedeep 29.257ms rfdc 0.511ms clone 0.576ms clone-deep 2.494ms deep-copy 0.451ms klona/full 0.408ms klona 0.265ms klona/lite 0.308ms klona/json 0.263ms Benchmark :: JSON JSON.stringify x 53,899 ops/sec ±0.76% (92 runs sampled) lodash x 46,800 ops/sec ±0.86% (90 runs sampled) rfdc x 221,456 ops/sec ±0.88% (92 runs sampled) clone x 39,537 ops/sec ±0.68% (92 runs sampled) clone/include x 25,488 ops/sec ±1.06% (88 runs sampled) clone-deep x 99,998 ops/sec ±0.91% (93 runs sampled) deep-copy x 141,270 ops/sec ±0.95% (92 runs sampled) klona/full x 55,016 ops/sec ±0.68% (94 runs sampled) klona x 281,215 ops/sec ±0.77% (93 runs sampled) klona/lite x 318,481 ops/sec ±0.72% (91 runs sampled) klona/json x 334,932 ops/sec ±0.66% (93 runs sampled) Benchmark :: LITE lodash x 36,992 ops/sec ±0.65% (91 runs sampled) clone x 35,974 ops/sec ±1.13% (88 runs sampled) clone/include x 22,609 ops/sec ±1.02% (91 runs sampled) clone-deep x 92,846 ops/sec ±0.66% (93 runs sampled) klona/full x 47,873 ops/sec ±0.83% (88 runs sampled) klona x 226,638 ops/sec ±1.16% (93 runs sampled) klona/lite x 257,900 ops/sec ±0.82% (93 runs sampled) Benchmark :: DEFAULT lodash x 55,914 ops/sec ±0.75% (93 runs sampled) ✘ Buffer ✘ Map keys clone x 92,127 ops/sec ±0.83% (94 runs sampled) ✘ DataView clone/include x 62,052 ops/sec ±0.88% (93 runs sampled) ✘ DataView klona/full x 90,308 ops/sec ±0.68% (89 runs sampled) klona x 230,257 ops/sec ±0.71% (91 runs sampled) Benchmark :: FULL lodash x 60,361 ops/sec ±0.65% (91 runs sampled) ✘ Buffer ✘ Map keys ✘ Missing non-enumerable Properties clone/include x 47,263 ops/sec ±0.85% (93 runs sampled) ✘ DataView ✘ Incorrect non-enumerable Properties klona/full x 82,346 ops/sec ±0.62% (93 runs sampled) ``` ## Related * [dlv](https://github.com/developit/dlv) – safely **read** from deep properties in 120 bytes * [dset](https://github.com/lukeed/dset) – safely **write** into deep properties in 160 bytes * [dequal](https://github.com/lukeed/dequal) – safely check for deep equality in 304 to 489 bytes ## License MIT © [Luke Edwards](https://lukeed.com) license000066600000002120150435264720006120 0ustar00MIT License Copyright (c) Luke Edwards (lukeed.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. dist/index.js000066600000003013150435264720007165 0ustar00function klona(x) { if (typeof x !== 'object') return x; var k, tmp, str=Object.prototype.toString.call(x); if (str === '[object Object]') { if (x.constructor !== Object && typeof x.constructor === 'function') { tmp = new x.constructor(); for (k in x) { if (x.hasOwnProperty(k) && tmp[k] !== x[k]) { tmp[k] = klona(x[k]); } } } else { tmp = {}; // null for (k in x) { if (k === '__proto__') { Object.defineProperty(tmp, k, { value: klona(x[k]), configurable: true, enumerable: true, writable: true, }); } else { tmp[k] = klona(x[k]); } } } return tmp; } if (str === '[object Array]') { k = x.length; for (tmp=Array(k); k--;) { tmp[k] = klona(x[k]); } return tmp; } if (str === '[object Set]') { tmp = new Set; x.forEach(function (val) { tmp.add(klona(val)); }); return tmp; } if (str === '[object Map]') { tmp = new Map; x.forEach(function (val, key) { tmp.set(klona(key), klona(val)); }); return tmp; } if (str === '[object Date]') { return new Date(+x); } if (str === '[object RegExp]') { tmp = new RegExp(x.source, x.flags); tmp.lastIndex = x.lastIndex; return tmp; } if (str === '[object DataView]') { return new x.constructor( klona(x.buffer) ); } if (str === '[object ArrayBuffer]') { return x.slice(0); } // ArrayBuffer.isView(x) // ~> `new` bcuz `Buffer.slice` => ref if (str.slice(-6) === 'Array]') { return new x.constructor(x); } return x; } exports.klona = klona;dist/index.mjs000066600000002773150435264720007356 0ustar00export function klona(x) { if (typeof x !== 'object') return x; var k, tmp, str=Object.prototype.toString.call(x); if (str === '[object Object]') { if (x.constructor !== Object && typeof x.constructor === 'function') { tmp = new x.constructor(); for (k in x) { if (x.hasOwnProperty(k) && tmp[k] !== x[k]) { tmp[k] = klona(x[k]); } } } else { tmp = {}; // null for (k in x) { if (k === '__proto__') { Object.defineProperty(tmp, k, { value: klona(x[k]), configurable: true, enumerable: true, writable: true, }); } else { tmp[k] = klona(x[k]); } } } return tmp; } if (str === '[object Array]') { k = x.length; for (tmp=Array(k); k--;) { tmp[k] = klona(x[k]); } return tmp; } if (str === '[object Set]') { tmp = new Set; x.forEach(function (val) { tmp.add(klona(val)); }); return tmp; } if (str === '[object Map]') { tmp = new Map; x.forEach(function (val, key) { tmp.set(klona(key), klona(val)); }); return tmp; } if (str === '[object Date]') { return new Date(+x); } if (str === '[object RegExp]') { tmp = new RegExp(x.source, x.flags); tmp.lastIndex = x.lastIndex; return tmp; } if (str === '[object DataView]') { return new x.constructor( klona(x.buffer) ); } if (str === '[object ArrayBuffer]') { return x.slice(0); } // ArrayBuffer.isView(x) // ~> `new` bcuz `Buffer.slice` => ref if (str.slice(-6) === 'Array]') { return new x.constructor(x); } return x; } dist/index.min.js000066600000002055150435264720007754 0ustar00!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.klona={})}(this,(function(e){e.klona=function e(t){if("object"!=typeof t)return t;var o,r,n=Object.prototype.toString.call(t);if("[object Object]"===n){if(t.constructor!==Object&&"function"==typeof t.constructor)for(o in r=new t.constructor,t)t.hasOwnProperty(o)&&r[o]!==t[o]&&(r[o]=e(t[o]));else for(o in r={},t)"__proto__"===o?Object.defineProperty(r,o,{value:e(t[o]),configurable:!0,enumerable:!0,writable:!0}):r[o]=e(t[o]);return r}if("[object Array]"===n){for(o=t.length,r=Array(o);o--;)r[o]=e(t[o]);return r}return"[object Set]"===n?(r=new Set,t.forEach((function(t){r.add(e(t))})),r):"[object Map]"===n?(r=new Map,t.forEach((function(t,o){r.set(e(o),e(t))})),r):"[object Date]"===n?new Date(+t):"[object RegExp]"===n?((r=new RegExp(t.source,t.flags)).lastIndex=t.lastIndex,r):"[object DataView]"===n?new t.constructor(e(t.buffer)):"[object ArrayBuffer]"===n?t.slice(0):"Array]"===n.slice(-6)?new t.constructor(t):t}}));json/index.js000066600000001155150435264720007200 0ustar00function klona(val) { var k, out, tmp; if (Array.isArray(val)) { out = Array(k=val.length); while (k--) out[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp; return out; } if (Object.prototype.toString.call(val) === '[object Object]') { out = {}; // null for (k in val) { if (k === '__proto__') { Object.defineProperty(out, k, { value: klona(val[k]), configurable: true, enumerable: true, writable: true, }); } else { out[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp; } } return out; } return val; } exports.klona = klona;json/index.mjs000066600000001135150435264720007353 0ustar00export function klona(val) { var k, out, tmp; if (Array.isArray(val)) { out = Array(k=val.length); while (k--) out[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp; return out; } if (Object.prototype.toString.call(val) === '[object Object]') { out = {}; // null for (k in val) { if (k === '__proto__') { Object.defineProperty(out, k, { value: klona(val[k]), configurable: true, enumerable: true, writable: true, }); } else { out[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp; } } return out; } return val; } json/index.min.js000066600000001036150435264720007760 0ustar00!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.klona={})}(this,(function(e){e.klona=function e(t){var o,r,n;if(Array.isArray(t)){for(r=Array(o=t.length);o--;)r[o]=(n=t[o])&&"object"==typeof n?e(n):n;return r}if("[object Object]"===Object.prototype.toString.call(t)){for(o in r={},t)"__proto__"===o?Object.defineProperty(r,o,{value:e(t[o]),configurable:!0,enumerable:!0,writable:!0}):r[o]=(n=t[o])&&"object"==typeof n?e(n):n;return r}return t}}));json/index.d.ts000066600000000046150435264720007432 0ustar00export function klona(input: T): T;index.d.ts000066600000000046150435264720006461 0ustar00export function klona(input: T): T;lite/index.js000066600000001741150435264720007165 0ustar00function klona(x) { if (typeof x !== 'object') return x; var k, tmp, str=Object.prototype.toString.call(x); if (str === '[object Object]') { if (x.constructor !== Object && typeof x.constructor === 'function') { tmp = new x.constructor(); for (k in x) { if (x.hasOwnProperty(k) && tmp[k] !== x[k]) { tmp[k] = klona(x[k]); } } } else { tmp = {}; // null for (k in x) { if (k === '__proto__') { Object.defineProperty(tmp, k, { value: klona(x[k]), configurable: true, enumerable: true, writable: true, }); } else { tmp[k] = klona(x[k]); } } } return tmp; } if (str === '[object Array]') { k = x.length; for (tmp=Array(k); k--;) { tmp[k] = klona(x[k]); } return tmp; } if (str === '[object Date]') { return new Date(+x); } if (str === '[object RegExp]') { tmp = new RegExp(x.source, x.flags); tmp.lastIndex = x.lastIndex; return tmp; } return x; } exports.klona = klona;lite/index.mjs000066600000001721150435264720007340 0ustar00export function klona(x) { if (typeof x !== 'object') return x; var k, tmp, str=Object.prototype.toString.call(x); if (str === '[object Object]') { if (x.constructor !== Object && typeof x.constructor === 'function') { tmp = new x.constructor(); for (k in x) { if (x.hasOwnProperty(k) && tmp[k] !== x[k]) { tmp[k] = klona(x[k]); } } } else { tmp = {}; // null for (k in x) { if (k === '__proto__') { Object.defineProperty(tmp, k, { value: klona(x[k]), configurable: true, enumerable: true, writable: true, }); } else { tmp[k] = klona(x[k]); } } } return tmp; } if (str === '[object Array]') { k = x.length; for (tmp=Array(k); k--;) { tmp[k] = klona(x[k]); } return tmp; } if (str === '[object Date]') { return new Date(+x); } if (str === '[object RegExp]') { tmp = new RegExp(x.source, x.flags); tmp.lastIndex = x.lastIndex; return tmp; } return x; } lite/index.min.js000066600000001417150435264720007747 0ustar00!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.klona={})}(this,(function(e){e.klona=function e(t){if("object"!=typeof t)return t;var o,n,r=Object.prototype.toString.call(t);if("[object Object]"===r){if(t.constructor!==Object&&"function"==typeof t.constructor)for(o in n=new t.constructor,t)t.hasOwnProperty(o)&&n[o]!==t[o]&&(n[o]=e(t[o]));else for(o in n={},t)"__proto__"===o?Object.defineProperty(n,o,{value:e(t[o]),configurable:!0,enumerable:!0,writable:!0}):n[o]=e(t[o]);return n}if("[object Array]"===r){for(o=t.length,n=Array(o);o--;)n[o]=e(t[o]);return n}return"[object Date]"===r?new Date(+t):"[object RegExp]"===r?((n=new RegExp(t.source,t.flags)).lastIndex=t.lastIndex,n):t}}));lite/index.d.ts000066600000000046150435264720007416 0ustar00export function klona(input: T): T;package.json000066600000003136150435264720007051 0ustar00{ "name": "klona", "version": "2.0.6", "repository": "lukeed/klona", "description": "A tiny (240B to 501B) and fast utility to \"deep clone\" Objects, Arrays, Dates, RegExps, and more!", "module": "dist/index.mjs", "unpkg": "dist/index.min.js", "main": "dist/index.js", "types": "index.d.ts", "license": "MIT", "author": { "name": "Luke Edwards", "email": "luke.edwards05@gmail.com", "url": "https://lukeed.com" }, "files": [ "*.d.ts", "dist", "full", "json", "lite" ], "exports": { ".": { "types": "./index.d.ts", "import": "./dist/index.mjs", "require": "./dist/index.js" }, "./json": { "types": "./index.d.ts", "import": "./json/index.mjs", "require": "./json/index.js" }, "./lite": { "types": "./index.d.ts", "import": "./lite/index.mjs", "require": "./lite/index.js" }, "./full": { "types": "./index.d.ts", "import": "./full/index.mjs", "require": "./full/index.js" }, "./package.json": "./package.json" }, "modes": { "json": "src/json.js", "lite": "src/lite.js", "default": "src/index.js", "full": "src/full.js" }, "engines": { "node": ">= 8" }, "scripts": { "build": "bundt", "pretest": "npm run build", "postbuild": "echo \"lite full json\" | xargs -n1 cp -v index.d.ts", "test": "uvu -r esm test -i suites" }, "keywords": [ "clone", "copy", "deep", "extend", "recursive", "object" ], "devDependencies": { "bundt": "1.0.2", "esm": "3.2.25", "uvu": "0.5.2" } }