@tamtamchik/json-deep-sort 1.2.1 → 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/dist/index.js CHANGED
@@ -23,23 +23,31 @@ __export(src_exports, {
23
23
  sort: () => sort
24
24
  });
25
25
  module.exports = __toCommonJS(src_exports);
26
- function sort(data, asc = true) {
27
- if (!data || typeof data !== "object") {
28
- return data;
29
- }
30
- if (Array.isArray(data)) {
31
- return data.map((item) => sort(item, asc));
32
- }
33
- if (isNonSortableObject(data)) {
34
- return data;
26
+ function sort(data, ascending = true) {
27
+ return sortRecursively(data, ascending);
28
+ }
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;
35
32
  }
36
- const sortedEntries = Object.entries(data).sort(([a], [b]) => asc ? a.localeCompare(b) : b.localeCompare(a));
37
- return Object.fromEntries(
38
- sortedEntries.map(([key, value]) => [key, sort(value, asc)])
39
- );
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)]));
40
47
  }
41
48
  function isNonSortableObject(obj) {
42
- return obj instanceof Date || obj instanceof RegExp || obj instanceof Function || obj instanceof Error || obj instanceof Map || obj instanceof Set || obj instanceof WeakMap || obj instanceof WeakSet || obj instanceof Promise || Symbol.iterator in Object(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);
43
51
  }
44
52
  // Annotate the CommonJS export names for ESM import in node:
45
53
  0 && (module.exports = {
package/dist/index.mjs CHANGED
@@ -1,21 +1,29 @@
1
1
  // src/index.ts
2
- function sort(data, asc = true) {
3
- if (!data || typeof data !== "object") {
4
- return data;
5
- }
6
- if (Array.isArray(data)) {
7
- return data.map((item) => sort(item, asc));
8
- }
9
- if (isNonSortableObject(data)) {
10
- return data;
2
+ function sort(data, ascending = true) {
3
+ return sortRecursively(data, ascending);
4
+ }
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;
11
8
  }
12
- const sortedEntries = Object.entries(data).sort(([a], [b]) => asc ? a.localeCompare(b) : b.localeCompare(a));
13
- return Object.fromEntries(
14
- sortedEntries.map(([key, value]) => [key, sort(value, asc)])
15
- );
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)]));
16
23
  }
17
24
  function isNonSortableObject(obj) {
18
- return obj instanceof Date || obj instanceof RegExp || obj instanceof Function || obj instanceof Error || obj instanceof Map || obj instanceof Set || obj instanceof WeakMap || obj instanceof WeakSet || obj instanceof Promise || Symbol.iterator in Object(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);
19
27
  }
20
28
  export {
21
29
  sort
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamtamchik/json-deep-sort",
3
- "version": "1.2.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.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,41 +1,43 @@
1
- /**
2
- * Function to sort JSON data.
3
- * @param {unknown} data - The data to be sorted.
4
- * @param {boolean} [asc=true] - Whether to sort in ascending order.
5
- * @returns {unknown} The sorted data.
6
- */
7
- export function sort(data: unknown, asc: boolean = true): unknown {
8
- if (!data || typeof data !== 'object') {
9
- return data;
10
- }
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>;
11
5
 
12
- if (Array.isArray(data)) {
13
- return data.map(item => sort(item, asc));
14
- }
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);
9
+ }
15
10
 
16
- if (isNonSortableObject(data)) {
17
- return data;
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;
18
15
  }
19
16
 
20
- const sortedEntries = Object.entries(data as Record<string, unknown>)
21
- .sort(([a], [b]) => asc ? a.localeCompare(b) : b.localeCompare(a));
17
+ return sortObject(data as ObjectType, ascending) as T;
18
+ }
19
+
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)];
22
28
 
23
- return Object.fromEntries(
24
- sortedEntries.map(([key, value]) => [key, sort(value, asc)])
25
- );
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)]));
26
37
  }
27
38
 
28
- function isNonSortableObject(obj: object): boolean {
29
- return (
30
- obj instanceof Date ||
31
- obj instanceof RegExp ||
32
- obj instanceof Function ||
33
- obj instanceof Error ||
34
- obj instanceof Map ||
35
- obj instanceof Set ||
36
- obj instanceof WeakMap ||
37
- obj instanceof WeakSet ||
38
- obj instanceof Promise ||
39
- Symbol.iterator in Object(obj)
40
- );
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);
41
43
  }