Skip to content

Commit 411ece3

Browse files
committed
1.2.0
1 parent 48e1278 commit 411ece3

File tree

4 files changed

+86
-125
lines changed

4 files changed

+86
-125
lines changed

Diff for: package-lock.json

+23-19
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tamtamchik/json-deep-sort",
3-
"version": "1.1.4",
3+
"version": "1.2.0",
44
"description": "A comprehensive utility for sorting JSON objects by keys.",
55
"main": "./dist/index.js",
66
"module": "./dist/index.mjs",
@@ -33,10 +33,10 @@
3333
],
3434
"devDependencies": {
3535
"@types/jest": "^29.5.12",
36-
"@types/node": "^20.14.11",
36+
"@types/node": "^22.3.0",
3737
"jest": "^29.7.0",
38-
"ts-jest": "^29.2.3",
39-
"tsup": "^8.2.2",
38+
"ts-jest": "^29.2.4",
39+
"tsup": "^8.2.4",
4040
"typescript": "^5.5.4"
4141
},
4242
"exports": {

Diff for: src/index.ts

+27-42
Original file line numberDiff line numberDiff line change
@@ -3,62 +3,47 @@
33
* @enum {string}
44
*/
55
enum DataType {
6-
OBJECT,
7-
ARRAY,
8-
STRING,
9-
OTHER,
6+
OBJECT = 'object',
7+
ARRAY = 'array',
8+
PRIMITIVE = 'primitive'
109
}
1110

1211
/**
1312
* Function to determine the data type of the provided data.
14-
* @param {any} data - The data to be checked.
13+
* @param {unknown} data - The data to be checked.
1514
* @returns {DataType} The DataType value corresponding to the data's type.
1615
*/
17-
function getType (data: any): DataType {
18-
if (Array.isArray(data)) {
19-
return DataType.ARRAY
20-
} else if (typeof data === 'object' && data !== null) {
21-
return DataType.OBJECT
22-
} else if (typeof data === 'string') {
23-
return DataType.STRING
24-
} else {
25-
return DataType.OTHER
26-
}
27-
}
28-
29-
/**
30-
* Function to determine whether the provided data is a recursive type.
31-
* @param {any} data - The data to be checked.
32-
* @returns {boolean} Whether the data is a recursive type.
33-
*/
34-
function isRecursiveType (data: any): boolean {
35-
return [DataType.OBJECT, DataType.ARRAY].includes(getType(data))
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;
3620
}
3721

3822
/**
3923
* Function to sort JSON data.
40-
* @param {any} data - The data to be sorted.
24+
* @param {unknown} data - The data to be sorted.
4125
* @param {boolean} [asc=true] - Whether to sort in ascending order.
42-
* @returns {any} The sorted data.
43-
* @throws {Error} If the data is not an object or array.
26+
* @returns {unknown} The sorted data.
4427
*/
45-
export function sort (data: any, asc: boolean = true): any {
46-
switch (getType(data)) {
28+
export function sort(data: unknown, asc: boolean = true): unknown {
29+
const type = getType(data);
4730

48-
case DataType.ARRAY:
49-
return data.map((d: any) => isRecursiveType(d) ? sort(d, asc) : d)
50-
51-
case DataType.OBJECT:
52-
const keys = Object.keys(data).sort()
53-
54-
if (!asc) keys.reverse()
31+
if (type === DataType.ARRAY) {
32+
return (data as unknown[]).map(item =>
33+
getType(item) !== DataType.PRIMITIVE ? sort(item, asc) : item
34+
);
35+
}
5536

56-
return keys.reduce((newData: any, key: string) => {
57-
newData[key] = isRecursiveType(data[key]) ? sort(data[key], asc) : data[key]
58-
return newData
59-
}, {})
37+
if (type === DataType.OBJECT) {
38+
const sortedKeys = Object.keys(data as object).sort();
39+
if (!asc) sortedKeys.reverse();
6040

61-
default:
62-
throw new Error('Invalid data type: expected an object or array of objects.')
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+
}, {});
6346
}
47+
48+
return data;
6449
}

Diff for: test/sort.test.ts

+32-60
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
import { sort } from '../src'
22

33
describe('sort', () => {
4-
it('should sort an object', () => {
5-
const input = { b: 'b', a: 'a' }
6-
const expected = { a: 'a', b: 'b' }
4+
it('should sort an object in ascending order by default', () => {
5+
const input = { c: 'c', b: 'b', a: 'a' }
6+
const expected = { a: 'a', b: 'b', c: 'c' }
77
expect(sort(input)).toEqual(expected)
88
})
99

10-
it('should not sort an simple array', () => {
11-
const input = ['a', 'b']
12-
const expected = ['a', 'b']
13-
expect(sort(input)).toEqual(expected)
10+
it('should sort an object in descending order when specified', () => {
11+
const input = { a: 'a', b: 'b', c: 'c' }
12+
const expected = { c: 'c', b: 'b', a: 'a' }
13+
expect(sort(input, false)).toEqual(expected)
14+
})
15+
16+
it('should not modify an array of primitives', () => {
17+
const input = ['b', 'a', 'c']
18+
expect(sort(input)).toEqual(input)
1419
})
1520

1621
it('should sort an array of objects', () => {
@@ -25,74 +30,41 @@ describe('sort', () => {
2530
expect(sort(input)).toEqual(expected)
2631
})
2732

28-
it('should sort an object with array values', () => {
33+
it('should sort nested objects', () => {
2934
const input = {
30-
b: ['b', 'a'],
31-
a: ['d', 'c', 'b', 'a'],
35+
b: { z: 'z', y: 'y' },
36+
a: { x: 'x', w: 'w' },
3237
}
3338
const expected = {
34-
a: ['d', 'c', 'b', 'a'],
35-
b: ['b', 'a'],
39+
a: { w: 'w', x: 'x' },
40+
b: { y: 'y', z: 'z' },
3641
}
3742
expect(sort(input)).toEqual(expected)
3843
})
3944

40-
it('should sort an object with nested objects', () => {
45+
it('should handle mixed nested structures', () => {
4146
const input = {
42-
a: 'a',
43-
b: {
44-
b: 'b',
45-
a: 'a',
46-
},
47+
b: ['b', 'a'],
48+
a: { d: 'd', c: 'c' },
4749
}
4850
const expected = {
49-
a: 'a',
50-
b: {
51-
a: 'a',
52-
b: 'b',
53-
},
51+
a: { c: 'c', d: 'd' },
52+
b: ['b', 'a'],
5453
}
5554
expect(sort(input)).toEqual(expected)
5655
})
5756

58-
it('should not sort an array of simple arrays', () => {
59-
const input = [
60-
['b', 'a'],
61-
['d', 'c', 'b', 'a'],
62-
]
63-
const expected = [
64-
['b', 'a'],
65-
['d', 'c', 'b', 'a'],
66-
]
67-
expect(sort(input)).toEqual(expected)
57+
it('should not throw an error for primitive inputs', () => {
58+
expect(() => sort('string')).not.toThrow()
59+
expect(() => sort(123)).not.toThrow()
60+
expect(() => sort(null)).not.toThrow()
61+
expect(() => sort(undefined)).not.toThrow()
6862
})
6963

70-
it('should sort an array containing objects', () => {
71-
const input = [
72-
{ b: 'b', a: 'a' },
73-
{ d: 'd', c: 'c', b: 'b', a: 'a' },
74-
]
75-
const expected = [
76-
{ a: 'a', b: 'b' },
77-
{ a: 'a', b: 'b', c: 'c', d: 'd' },
78-
]
79-
expect(sort(input)).toEqual(expected)
80-
})
81-
82-
it('should sort an object in descending order', () => {
83-
const input = { b: 'b', a: 'a', c: 'c' }
84-
const expected = { c: 'c', b: 'b', a: 'a' }
85-
expect(sort(input, false)).toEqual(expected)
86-
})
87-
88-
it('should throw an error for non-object, non-array input', () => {
89-
const input = 'string'
90-
expect(() => sort(input)).toThrow('Invalid data type: expected an object or array of objects.')
91-
92-
const inputNumber = 123
93-
expect(() => sort(inputNumber)).toThrow('Invalid data type: expected an object or array of objects.')
94-
95-
const inputNull = null
96-
expect(() => sort(inputNull)).toThrow('Invalid data type: expected an object or array of objects.')
64+
it('should return primitive inputs unchanged', () => {
65+
expect(sort('string')).toBe('string')
66+
expect(sort(123)).toBe(123)
67+
expect(sort(null)).toBe(null)
68+
expect(sort(undefined)).toBe(undefined)
9769
})
9870
})

0 commit comments

Comments
 (0)