@tamtamchik/json-deep-sort 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -13
- package/dist/index.js +23 -20
- package/dist/index.mjs +23 -20
- package/package.json +5 -5
- package/src/index.ts +35 -41
package/README.md
CHANGED
|
@@ -8,9 +8,15 @@
|
|
|
8
8
|
[![Software License][ico-license]](LICENSE)
|
|
9
9
|
[![Total Downloads][ico-downloads]][link-downloads]
|
|
10
10
|
|
|
11
|
-
JSON Deep Sort is a
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
JSON Deep Sort is a powerful and versatile TypeScript package designed for efficient sorting of JSON objects by keys. It offers:
|
|
12
|
+
|
|
13
|
+
- Comprehensive handling of deeply nested objects and arrays
|
|
14
|
+
- Flexible sorting options, including ascending and descending order
|
|
15
|
+
- Support for both synchronous and asynchronous operations
|
|
16
|
+
- Preservation of non-sortable objects (e.g., Date, RegExp, Function)
|
|
17
|
+
- Lightweight implementation with zero dependencies
|
|
18
|
+
|
|
19
|
+
Whether you're working with simple flat objects or complex nested structures, JSON Deep Sort provides a reliable solution for organizing your data.
|
|
14
20
|
|
|
15
21
|
## Installation
|
|
16
22
|
|
|
@@ -37,19 +43,38 @@ import { sort } from '@tamtamchik/json-deep-sort';
|
|
|
37
43
|
Here is an example of sorting a JSON object:
|
|
38
44
|
|
|
39
45
|
```typescript
|
|
40
|
-
|
|
46
|
+
// Example 1: Sorting a simple object
|
|
47
|
+
const simpleData = { b: 'b', a: 'a', c: 'c' };
|
|
48
|
+
console.log(sort(simpleData));
|
|
49
|
+
// Output: { a: 'a', b: 'b', c: 'c' }
|
|
50
|
+
|
|
51
|
+
// Example 2: Sorting a nested object
|
|
52
|
+
const nestedData = {
|
|
41
53
|
b: 'b',
|
|
42
54
|
a: 'a',
|
|
43
|
-
c: {
|
|
44
|
-
d: 'd',
|
|
45
|
-
c: 'c',
|
|
46
|
-
a: 'a',
|
|
47
|
-
b: 'b'
|
|
48
|
-
}
|
|
55
|
+
c: { d: 'd', c: 'c', a: 'a', b: 'b' }
|
|
49
56
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
console.log(sort(nestedData));
|
|
58
|
+
// Output: { a: 'a', b: 'b', c: { a: 'a', b: 'b', c: 'c', d: 'd' } }
|
|
59
|
+
|
|
60
|
+
// Example 3: Sorting an array of objects
|
|
61
|
+
const arrayData = [{ b: 'b', a: 'a' }, { d: 'd', c: 'c' }];
|
|
62
|
+
console.log(sort(arrayData));
|
|
63
|
+
// Output: [{ a: 'a', b: 'b' }, { c: 'c', d: 'd' }]
|
|
64
|
+
|
|
65
|
+
// Example 4: Sorting in descending order
|
|
66
|
+
const descendingData = { a: 'a', c: 'c', b: 'b' };
|
|
67
|
+
console.log(sort(descendingData, false));
|
|
68
|
+
// Output: { c: 'c', b: 'b', a: 'a' }
|
|
69
|
+
|
|
70
|
+
// Example 5: Handling mixed data types
|
|
71
|
+
const mixedData = {
|
|
72
|
+
b: [3, 1, 2],
|
|
73
|
+
a: { z: 'z', y: 'y' },
|
|
74
|
+
c: new Date('2023-01-01')
|
|
75
|
+
};
|
|
76
|
+
console.log(sort(mixedData));
|
|
77
|
+
// Output: { a: { y: 'y', z: 'z' }, b: [3, 1, 2], c: Date('2023-01-01') }
|
|
53
78
|
```
|
|
54
79
|
|
|
55
80
|
## Contributing
|
package/dist/index.js
CHANGED
|
@@ -23,28 +23,31 @@ __export(src_exports, {
|
|
|
23
23
|
sort: () => sort
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(src_exports);
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
if (data !== null && typeof data === "object") return "object" /* OBJECT */;
|
|
29
|
-
return "primitive" /* PRIMITIVE */;
|
|
26
|
+
function sort(data, ascending = true) {
|
|
27
|
+
return sortRecursively(data, ascending);
|
|
30
28
|
}
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return data.map(
|
|
35
|
-
(item) => getType(item) !== "primitive" /* PRIMITIVE */ ? sort(item, asc) : item
|
|
36
|
-
);
|
|
29
|
+
function sortRecursively(data, ascending) {
|
|
30
|
+
if (!isObject(data) || Array.isArray(data) || isNonSortableObject(data)) {
|
|
31
|
+
return Array.isArray(data) ? data.map((item) => sortRecursively(item, ascending)) : data;
|
|
37
32
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
return sortObject(data, ascending);
|
|
34
|
+
}
|
|
35
|
+
function isObject(data) {
|
|
36
|
+
return typeof data === "object" && data !== null;
|
|
37
|
+
}
|
|
38
|
+
function sortObject(obj, ascending) {
|
|
39
|
+
const entries = [...Object.entries(obj), ...Object.getOwnPropertySymbols(obj).map((sym) => [sym, obj[sym]])];
|
|
40
|
+
const sortedEntries = entries.sort(([keyA], [keyB]) => {
|
|
41
|
+
if (typeof keyA === "symbol" && typeof keyB === "symbol") return 0;
|
|
42
|
+
if (typeof keyA === "symbol") return 1;
|
|
43
|
+
if (typeof keyB === "symbol") return -1;
|
|
44
|
+
return ascending ? keyA.localeCompare(keyB) : keyB.localeCompare(keyA);
|
|
45
|
+
});
|
|
46
|
+
return Object.fromEntries(sortedEntries.map(([key, value]) => [key, sortRecursively(value, ascending)]));
|
|
47
|
+
}
|
|
48
|
+
function isNonSortableObject(obj) {
|
|
49
|
+
const nonSortableTypes = [Date, RegExp, Function, Error, Map, Set, WeakMap, WeakSet, Promise];
|
|
50
|
+
return nonSortableTypes.some((type) => obj instanceof type) || Symbol.iterator in Object(obj);
|
|
48
51
|
}
|
|
49
52
|
// Annotate the CommonJS export names for ESM import in node:
|
|
50
53
|
0 && (module.exports = {
|
package/dist/index.mjs
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
function
|
|
3
|
-
|
|
4
|
-
if (data !== null && typeof data === "object") return "object" /* OBJECT */;
|
|
5
|
-
return "primitive" /* PRIMITIVE */;
|
|
2
|
+
function sort(data, ascending = true) {
|
|
3
|
+
return sortRecursively(data, ascending);
|
|
6
4
|
}
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return data.map(
|
|
11
|
-
(item) => getType(item) !== "primitive" /* PRIMITIVE */ ? sort(item, asc) : item
|
|
12
|
-
);
|
|
5
|
+
function sortRecursively(data, ascending) {
|
|
6
|
+
if (!isObject(data) || Array.isArray(data) || isNonSortableObject(data)) {
|
|
7
|
+
return Array.isArray(data) ? data.map((item) => sortRecursively(item, ascending)) : data;
|
|
13
8
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
return sortObject(data, ascending);
|
|
10
|
+
}
|
|
11
|
+
function isObject(data) {
|
|
12
|
+
return typeof data === "object" && data !== null;
|
|
13
|
+
}
|
|
14
|
+
function sortObject(obj, ascending) {
|
|
15
|
+
const entries = [...Object.entries(obj), ...Object.getOwnPropertySymbols(obj).map((sym) => [sym, obj[sym]])];
|
|
16
|
+
const sortedEntries = entries.sort(([keyA], [keyB]) => {
|
|
17
|
+
if (typeof keyA === "symbol" && typeof keyB === "symbol") return 0;
|
|
18
|
+
if (typeof keyA === "symbol") return 1;
|
|
19
|
+
if (typeof keyB === "symbol") return -1;
|
|
20
|
+
return ascending ? keyA.localeCompare(keyB) : keyB.localeCompare(keyA);
|
|
21
|
+
});
|
|
22
|
+
return Object.fromEntries(sortedEntries.map(([key, value]) => [key, sortRecursively(value, ascending)]));
|
|
23
|
+
}
|
|
24
|
+
function isNonSortableObject(obj) {
|
|
25
|
+
const nonSortableTypes = [Date, RegExp, Function, Error, Map, Set, WeakMap, WeakSet, Promise];
|
|
26
|
+
return nonSortableTypes.some((type) => obj instanceof type) || Symbol.iterator in Object(obj);
|
|
24
27
|
}
|
|
25
28
|
export {
|
|
26
29
|
sort
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamtamchik/json-deep-sort",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A comprehensive utility for sorting JSON objects by keys.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"json-tools"
|
|
33
33
|
],
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@types/jest": "^29.5.
|
|
36
|
-
"@types/node": "^22.
|
|
35
|
+
"@types/jest": "^29.5.13",
|
|
36
|
+
"@types/node": "^22.7.5",
|
|
37
37
|
"jest": "^29.7.0",
|
|
38
38
|
"ts-jest": "^29.2.4",
|
|
39
|
-
"tsup": "^8.
|
|
40
|
-
"typescript": "^5.
|
|
39
|
+
"tsup": "^8.3.0",
|
|
40
|
+
"typescript": "^5.6.3"
|
|
41
41
|
},
|
|
42
42
|
"exports": {
|
|
43
43
|
".": {
|
package/src/index.ts
CHANGED
|
@@ -1,49 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
enum DataType {
|
|
6
|
-
OBJECT = 'object',
|
|
7
|
-
ARRAY = 'array',
|
|
8
|
-
PRIMITIVE = 'primitive'
|
|
9
|
-
}
|
|
1
|
+
// Type definitions for object types and non-sortable types
|
|
2
|
+
type ObjectType = Record<string | symbol, unknown>;
|
|
3
|
+
type SortedEntry = [string | symbol, unknown];
|
|
4
|
+
type NonSortableType = Date | RegExp | Function | Error | Map<unknown, unknown> | Set<unknown> | WeakMap<object, unknown> | WeakSet<object> | Promise<unknown>;
|
|
10
5
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* @returns {DataType} The DataType value corresponding to the data's type.
|
|
15
|
-
*/
|
|
16
|
-
function getType(data: unknown): DataType {
|
|
17
|
-
if (Array.isArray(data)) return DataType.ARRAY;
|
|
18
|
-
if (data !== null && typeof data === 'object') return DataType.OBJECT;
|
|
19
|
-
return DataType.PRIMITIVE;
|
|
6
|
+
// Main sorting function that can handle various data types
|
|
7
|
+
export function sort<T>(data: T, ascending = true): T {
|
|
8
|
+
return sortRecursively(data, ascending);
|
|
20
9
|
}
|
|
21
10
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* @returns {unknown} The sorted data.
|
|
27
|
-
*/
|
|
28
|
-
export function sort(data: unknown, asc: boolean = true): unknown {
|
|
29
|
-
const type = getType(data);
|
|
30
|
-
|
|
31
|
-
if (type === DataType.ARRAY) {
|
|
32
|
-
return (data as unknown[]).map(item =>
|
|
33
|
-
getType(item) !== DataType.PRIMITIVE ? sort(item, asc) : item
|
|
34
|
-
);
|
|
11
|
+
// Recursive function to sort nested structures
|
|
12
|
+
function sortRecursively<T>(data: T, ascending: boolean): T {
|
|
13
|
+
if (!isObject(data) || Array.isArray(data) || isNonSortableObject(data)) {
|
|
14
|
+
return Array.isArray(data) ? data.map(item => sortRecursively(item, ascending)) as T : data;
|
|
35
15
|
}
|
|
36
16
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (!asc) sortedKeys.reverse();
|
|
17
|
+
return sortObject(data as ObjectType, ascending) as T;
|
|
18
|
+
}
|
|
40
19
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
20
|
+
// Helper function to check if a value is an object
|
|
21
|
+
function isObject(data: unknown): data is ObjectType {
|
|
22
|
+
return typeof data === 'object' && data !== null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Function to sort object properties
|
|
26
|
+
function sortObject(obj: ObjectType, ascending: boolean): ObjectType {
|
|
27
|
+
const entries = [...Object.entries(obj), ...Object.getOwnPropertySymbols(obj).map(sym => [sym, obj[sym]] as SortedEntry)];
|
|
28
|
+
|
|
29
|
+
const sortedEntries = entries.sort(([keyA], [keyB]) => {
|
|
30
|
+
if (typeof keyA === 'symbol' && typeof keyB === 'symbol') return 0;
|
|
31
|
+
if (typeof keyA === 'symbol') return 1;
|
|
32
|
+
if (typeof keyB === 'symbol') return -1;
|
|
33
|
+
return ascending ? (keyA as string).localeCompare(keyB as string) : (keyB as string).localeCompare(keyA as string);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return Object.fromEntries(sortedEntries.map(([key, value]) => [key, sortRecursively(value, ascending)]));
|
|
37
|
+
}
|
|
47
38
|
|
|
48
|
-
|
|
39
|
+
// Helper function to check if an object is of a non-sortable type
|
|
40
|
+
function isNonSortableObject(obj: unknown): obj is NonSortableType {
|
|
41
|
+
const nonSortableTypes = [Date, RegExp, Function, Error, Map, Set, WeakMap, WeakSet, Promise];
|
|
42
|
+
return nonSortableTypes.some(type => obj instanceof type) || Symbol.iterator in Object(obj);
|
|
49
43
|
}
|