Skip to content

Commit

Permalink
feat: add "full" mode;
Browse files Browse the repository at this point in the history
- handles symbols, accessors, non-enumerables
- add initial `Symbol` tests
- 507B -- 52k op/s
  • Loading branch information
lukeed committed Aug 14, 2020
1 parent 4fc79fd commit 1a85948
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ node_modules
/dist
/json
/lite
/full
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
],
"modes": {
"json": "src/json.js",
"lite": "src/lite.js",
"default": "src/index.js",
"lite": "src/lite.js"
"full": "src/full.js"
},
"engines": {
"node": ">= 8"
Expand Down
53 changes: 53 additions & 0 deletions src/full.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
function 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 = typeof x.constructor === 'function' ? new x.constructor() : Object.create(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;
}
27 changes: 27 additions & 0 deletions test/full.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as suites from './suites';
import { klona } from '../src/full';

suites.API(klona);

suites.Strings(klona);
suites.Booleans(klona);
suites.Numbers(klona);
suites.Nully(klona);

suites.Dates(klona);
suites.RegExps(klona);

suites.Objects(klona);
suites.Arrays(klona);

suites.Functions(klona);
suites.Pollutions(klona);
suites.Classes(klona);

suites.Maps(klona);
suites.Sets(klona);

suites.TypedArrays(klona);

suites.Symbols(klona);
// suites.Descriptors(klona);
1 change: 1 addition & 0 deletions test/suites/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { default as Maps } from './map';
export { default as Sets } from './set';

export { default as TypedArrays } from './typedarray';
export { default as Symbols } from './symbol';

export { default as Dates } from './date';
export { default as RegExps } from './regexp';
Expand Down
27 changes: 27 additions & 0 deletions test/suites/symbol.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { suite } from 'uvu';
import * as assert from 'assert';

export default function (klona) {
const Symbols = suite('Symbol');

Symbols('direct', () => {
const input = Symbol('input');
const output = klona(input);

assert.deepStrictEqual(input, output);
});

// https://github.com/lukeed/klona/issues/16
Symbols('object :: enumerable key', () => {
const key = Symbol('key');
const input = { foo: 123, [key]: 456 };
console.log('START');
const output = klona(input);
console.log('~> output', output);

assert.equal(output[key], 456);
assert.deepStrictEqual(input, output);
});

Symbols.run();
}

0 comments on commit 1a85948

Please sign in to comment.