nhb-toolbox
Version:
A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.
106 lines (105 loc) • 4.42 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.naturalSort = naturalSort;
exports.sortAnArray = sortAnArray;
const non_primitives_1 = require("../guards/non-primitives");
const primitives_1 = require("../guards/primitives");
function naturalSort(a, b, options) {
const { caseInsensitive = true, localeAware = false } = options || {};
const _createChunks = (str) => {
const chunks = [];
let current = '';
let isNumeric = false;
for (const char of str) {
const charIsNum = !Number.isNaN(Number(char));
if (current?.length === 0) {
current = char;
isNumeric = charIsNum;
continue;
}
if (charIsNum === isNumeric) {
current += char;
}
else {
chunks?.push(isNumeric ? Number(current) : current);
current = char;
isNumeric = charIsNum;
}
}
if (current?.length > 0) {
chunks?.push(isNumeric ? Number(current) : current);
}
return chunks;
};
const aChunks = _createChunks(a);
const bChunks = _createChunks(b);
for (let i = 0; i < Math.min(aChunks?.length, bChunks?.length); i++) {
let aChunk = aChunks[i];
let bChunk = bChunks[i];
if (caseInsensitive && (0, primitives_1.isString)(aChunk) && (0, primitives_1.isString)(bChunk)) {
aChunk = aChunk?.toLowerCase();
bChunk = bChunk?.toLowerCase();
}
if (typeof aChunk !== typeof bChunk) {
return (0, primitives_1.isString)(aChunk) ? 1 : -1;
}
if (aChunk !== bChunk) {
if ((0, primitives_1.isNumber)(aChunk) && (0, primitives_1.isNumber)(bChunk)) {
return aChunk - bChunk;
}
if ((0, primitives_1.isString)(aChunk) && (0, primitives_1.isString)(bChunk)) {
if (localeAware) {
const cmp = aChunk.localeCompare(bChunk, undefined, {
sensitivity: caseInsensitive ? 'accent' : 'variant',
});
if (cmp !== 0)
return cmp;
}
return aChunk < bChunk ? -1 : 1;
}
}
}
return aChunks?.length - bChunks?.length;
}
function sortAnArray(array, options) {
if (!(0, non_primitives_1.isValidArray)(array))
return array;
if ((0, non_primitives_1.isArrayOfType)(array, primitives_1.isString)) {
return [...array].sort((a, b) => options?.sortOrder === 'desc' ? naturalSort(b, a) : naturalSort(a, b));
}
if ((0, non_primitives_1.isArrayOfType)(array, primitives_1.isNumber)) {
return [...array].sort((a, b) => (options?.sortOrder === 'desc' ? b - a : a - b));
}
if ((0, non_primitives_1.isArrayOfType)(array, primitives_1.isBoolean)) {
return [...array].sort((a, b) => options?.sortOrder === 'desc' ? Number(b) - Number(a) : Number(a) - Number(b));
}
if ((0, non_primitives_1.isArrayOfType)(array, non_primitives_1.isObject) && options && 'sortByField' in options) {
return [...array].sort((a, b) => {
const _getKeyValue = (obj, path) => {
return path
.split('.')
.reduce((acc, key) => acc?.[key], obj);
};
const keyA = _getKeyValue(a, options?.sortByField);
const keyB = _getKeyValue(b, options?.sortByField);
if (keyA == null || keyB == null) {
return keyA == null ? 1 : -1;
}
if ((0, primitives_1.isString)(keyA) && (0, primitives_1.isString)(keyB)) {
return options?.sortOrder === 'desc'
? naturalSort(keyB, keyA)
: naturalSort(keyA, keyB);
}
if ((0, primitives_1.isNumber)(keyA) && (0, primitives_1.isNumber)(keyB)) {
return options?.sortOrder === 'desc' ? keyB - keyA : keyA - keyB;
}
if ((0, primitives_1.isBoolean)(keyA) && (0, primitives_1.isBoolean)(keyB)) {
return options?.sortOrder === 'desc'
? Number(keyB) - Number(keyA)
: Number(keyA) - Number(keyB);
}
return 0;
});
}
return [...array];
}