Skip to content

Commit

Permalink
Preserve property descriptors (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
papb authored Dec 30, 2020
1 parent 4bd07b0 commit 4e95b31
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 9 deletions.
11 changes: 8 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,18 @@ module.exports = (object, options = {}) => {

for (const key of keys) {
const value = object[key];
let newValue;

if (deep && Array.isArray(value)) {
result[key] = deepSortArray(value);
continue;
newValue = deepSortArray(value);
} else {
newValue = deep && isPlainObject(value) ? sortKeys(value) : value;
}

result[key] = deep && isPlainObject(value) ? sortKeys(value) : value;
Object.defineProperty(result, key, {
...Object.getOwnPropertyDescriptor(object, key),
value: newValue
});
}

return result;
Expand Down
69 changes: 63 additions & 6 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,49 @@
import test from 'ava';
import sortKeys from '.';

function deepEqualInOrder(t, actual, expected) {
t.deepEqual(actual, expected);

const seen = new Set();

function assertSameKeysInOrder(object1, object2) {
// This function assumes the objects given are already deep equal.

if (seen.has(object1) && seen.has(object2)) {
return;
}

seen.add(object1);
seen.add(object2);

if (Array.isArray(object1)) {
for (const index of object1.keys()) {
assertSameKeysInOrder(object1[index], object2[index]);
}
} else if (typeof object1 === 'object') {
const keys1 = Object.keys(object1);
const keys2 = Object.keys(object2);
t.deepEqual(keys1, keys2);
for (const index of keys1.keys()) {
assertSameKeysInOrder(object1[keys1[index]], object2[keys2[index]]);
}
}
}

assertSameKeysInOrder(actual, expected);
}

test('sort the keys of an object', t => {
t.deepEqual(sortKeys({c: 0, a: 0, b: 0}), {a: 0, b: 0, c: 0});
deepEqualInOrder(t, sortKeys({c: 0, a: 0, b: 0}), {a: 0, b: 0, c: 0});
});

test('custom compare function', t => {
const compare = (a, b) => a.localeCompare(b);
t.deepEqual(sortKeys({c: 0, a: 0, b: 0}, {compare}), {c: 0, b: 0, a: 0});
const compare = (a, b) => b.localeCompare(a);
deepEqualInOrder(t, sortKeys({c: 0, a: 0, b: 0}, {compare}), {c: 0, b: 0, a: 0});
});

test('deep option', t => {
t.deepEqual(sortKeys({c: {c: 0, a: 0, b: 0}, a: 0, b: 0}, {deep: true}), {a: 0, b: 0, c: {a: 0, b: 0, c: 0}});
deepEqualInOrder(t, sortKeys({c: {c: 0, a: 0, b: 0}, a: 0, b: 0}, {deep: true}), {a: 0, b: 0, c: {a: 0, b: 0, c: 0}});

t.notThrows(() => {
const object = {a: 0};
Expand Down Expand Up @@ -47,10 +79,10 @@ test('deep option', t => {
const deepSorted = sortKeys(object3, {deep: true});

t.is(sorted, sorted.a.c);
t.deepEqual(deepSorted.a[0], deepSorted.a[0].a.c);
deepEqualInOrder(t, deepSorted.a[0], deepSorted.a[0].a.c);
t.deepEqual(Object.keys(sorted), ['a', 'b']);
t.deepEqual(Object.keys(deepSorted.a[0]), ['a', 'b']);
t.deepEqual(sortKeys({c: {c: 0, a: 0, b: 0}, a: 0, b: 0, z: [9, 8, 7, 6, 5]}, {deep: true}), {a: 0, b: 0, c: {a: 0, b: 0, c: 0}, z: [9, 8, 7, 6, 5]});
deepEqualInOrder(t, sortKeys({c: {c: 0, a: 0, b: 0}, a: 0, b: 0, z: [9, 8, 7, 6, 5]}, {deep: true}), {a: 0, b: 0, c: {a: 0, b: 0, c: 0}, z: [9, 8, 7, 6, 5]});
t.deepEqual(Object.keys(sortKeys({a: [{b: 0, a: 0}]}, {deep: true}).a[0]), ['a', 'b']);
});

Expand Down Expand Up @@ -91,3 +123,28 @@ test('top-level array', t => {
t.deepEqual(Object.keys(deepSorted[0]), ['a', 'b']);
t.deepEqual(Object.keys(deepSorted[1]), ['c', 'd']);
});

test('keeps property descriptors intact', t => {
const descriptors = {
b: {
value: 1,
configurable: true,
enumerable: true,
writable: false
},
a: {
value: 2,
configurable: false,
enumerable: true,
writable: true
}
};

const object = {};
Object.defineProperties(object, descriptors);

const sorted = sortKeys(object);

deepEqualInOrder(t, sorted, {a: 2, b: 1});
t.deepEqual(Object.getOwnPropertyDescriptors(sorted), descriptors);
});

0 comments on commit 4e95b31

Please sign in to comment.