@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 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 comprehensive package that provides flexible sorting of JSON objects by keys. This
12
- TypeScript-written package can handle deeply nested objects and arrays, and offers both synchronous and asynchronous
13
- operations.
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
- let data = {
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
- let sortedData = sort(data, true);
52
- // { a: 'a', b: 'b', c: { a: 'a', b: 'b', c: 'c', d: 'd' } }
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 getType(data) {
27
- if (Array.isArray(data)) return "array" /* ARRAY */;
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 sort(data, asc = true) {
32
- const type = getType(data);
33
- if (type === "array" /* ARRAY */) {
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
- if (type === "object" /* OBJECT */) {
39
- const sortedKeys = Object.keys(data).sort();
40
- if (!asc) sortedKeys.reverse();
41
- return sortedKeys.reduce((result, key) => {
42
- const value = data[key];
43
- result[key] = getType(value) !== "primitive" /* PRIMITIVE */ ? sort(value, asc) : value;
44
- return result;
45
- }, {});
46
- }
47
- return data;
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 getType(data) {
3
- if (Array.isArray(data)) return "array" /* ARRAY */;
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 sort(data, asc = true) {
8
- const type = getType(data);
9
- if (type === "array" /* ARRAY */) {
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
- if (type === "object" /* OBJECT */) {
15
- const sortedKeys = Object.keys(data).sort();
16
- if (!asc) sortedKeys.reverse();
17
- return sortedKeys.reduce((result, key) => {
18
- const value = data[key];
19
- result[key] = getType(value) !== "primitive" /* PRIMITIVE */ ? sort(value, asc) : value;
20
- return result;
21
- }, {});
22
- }
23
- return data;
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.2.0",
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.12",
36
- "@types/node": "^22.3.0",
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.2.4",
40
- "typescript": "^5.5.4"
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
- * Enumeration of data types.
3
- * @enum {string}
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
- * Function to determine the data type of the provided data.
13
- * @param {unknown} data - The data to be checked.
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
- * Function to sort JSON data.
24
- * @param {unknown} data - The data to be sorted.
25
- * @param {boolean} [asc=true] - Whether to sort in ascending order.
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
- if (type === DataType.OBJECT) {
38
- const sortedKeys = Object.keys(data as object).sort();
39
- if (!asc) sortedKeys.reverse();
17
+ return sortObject(data as ObjectType, ascending) as T;
18
+ }
40
19
 
41
- return sortedKeys.reduce((result: Record<string, unknown>, key) => {
42
- const value = (data as Record<string, unknown>)[key];
43
- result[key] = getType(value) !== DataType.PRIMITIVE ? sort(value, asc) : value;
44
- return result;
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
- return data;
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
  }